#pragma once
+#include <type_traits>
+
#include <folly/wangle/channel/Pipeline.h>
namespace folly { namespace wangle {
explicit StaticPipeline(bool) : Pipeline<R, W>(true) {}
};
+template <class Handler>
+class BaseWithOptional {
+ protected:
+ folly::Optional<Handler> handler_;
+};
+
+template <class Handler>
+class BaseWithoutOptional {
+};
+
template <class R, class W, class Handler, class... Handlers>
class StaticPipeline<R, W, Handler, Handlers...>
- : public StaticPipeline<R, W, Handlers...> {
+ : public StaticPipeline<R, W, Handlers...>
+ , public std::conditional<std::is_abstract<Handler>::value,
+ BaseWithoutOptional<Handler>,
+ BaseWithOptional<Handler>>::type {
public:
template <class... HandlerArgs>
explicit StaticPipeline(HandlerArgs&&... handlers)
Handler
>::value>::type
setHandler(HandlerArg&& arg) {
- handler_.emplace(std::forward<HandlerArg>(arg));
- handlerPtr_ = std::shared_ptr<Handler>(&(*handler_), [](Handler*){});
+ BaseWithOptional<Handler>::handler_.emplace(std::forward<HandlerArg>(arg));
+ handlerPtr_ = std::shared_ptr<Handler>(&(*BaseWithOptional<Handler>::handler_), [](Handler*){});
}
template <class HandlerArg>
}
bool isFirst_;
- folly::Optional<Handler> handler_;
std::shared_ptr<Handler> handlerPtr_;
typename ContextType<Handler, Pipeline<R, W>>::type ctx_;
};
using namespace testing;
typedef StrictMock<MockHandlerAdapter<int, int>> IntHandler;
+class IntHandler2 : public StrictMock<MockHandlerAdapter<int, int>> {};
ACTION(FireRead) {
arg0->fireRead(arg1);
// Test that handlers correctly fire the next handler when directed
TEST(PipelineTest, FireActions) {
IntHandler handler1;
- IntHandler handler2;
+ IntHandler2 handler2;
{
InSequence sequence;
EXPECT_CALL(handler1, attachPipeline(_));
}
- StaticPipeline<int, int, IntHandler, IntHandler>
+ StaticPipeline<int, int, IntHandler, IntHandler2>
pipeline(&handler1, &handler2);
EXPECT_CALL(handler1, read_(_, _)).WillOnce(FireRead());
// Test having the last read handler turn around and write
TEST(PipelineTest, TurnAround) {
IntHandler handler1;
- IntHandler handler2;
+ IntHandler2 handler2;
{
InSequence sequence;
EXPECT_CALL(handler1, attachPipeline(_));
}
- StaticPipeline<int, int, IntHandler, IntHandler>
+ StaticPipeline<int, int, IntHandler, IntHandler2>
pipeline(&handler1, &handler2);
EXPECT_CALL(handler1, read_(_, _)).WillOnce(FireRead());
}
TEST(PipelineTest, HandlerInPipelineTwice) {
- IntHandler handler;
- EXPECT_CALL(handler, attachPipeline(_)).Times(2);
- StaticPipeline<int, int, IntHandler, IntHandler> pipeline(&handler, &handler);
- EXPECT_FALSE(handler.getContext());
- EXPECT_CALL(handler, detachPipeline(_)).Times(2);
+ auto handler = std::make_shared<IntHandler>();
+ EXPECT_CALL(*handler, attachPipeline(_)).Times(2);
+ Pipeline<int, int> pipeline;
+ pipeline.addBack(handler);
+ pipeline.addBack(handler);
+ pipeline.finalize();
+ EXPECT_FALSE(handler->getContext());
+ EXPECT_CALL(*handler, detachPipeline(_)).Times(2);
}
TEST(PipelineTest, NoDetachOnOwner) {
TEST(Pipeline, DynamicConstruction) {
{
- StaticPipeline<std::string, std::string, StringHandler, StringHandler>
- pipeline{StringHandler(), StringHandler()};
+ Pipeline<std::string, std::string> pipeline;
+ pipeline.addBack(StringHandler());
+ pipeline.addBack(StringHandler());
// Exercise both addFront and addBack. Final pipeline is
// StI <-> ItS <-> StS <-> StS <-> StI <-> ItS