text: /*
   * A test for so_drop_subscription_for_all_states for deadletter handlers.
   */
  
  #include <so_5/all.hpp>
  
  #include <test/3rd_party/various_helpers/time_limited_execution.hpp>
  #include <test/3rd_party/various_helpers/ensure.hpp>
  
  #include "../deadletter_handler_common.hpp"
  
  class test_message final : public so_5::message_t {};
  
  class test_signal final : public so_5::signal_t {};
  
  class finish final : public so_5::signal_t {};
  
  class nontemplate_basic_part_t : public so_5::agent_t
  {
  protected:
  	state_t st_test{ this, "test" };
  
  	int m_deadletters{ 0 };
  
  	void
  	actual_deadletter_handler()
  	{
  		ensure_or_die( 0 == m_deadletters, "m_deadletters must be 0" );
  		++m_deadletters;
  
  		do_next_step();
  		so_5::send<finish>(*this);
  	}
  
  	virtual void
  	do_next_step() = 0;
  
  public:
  	nontemplate_basic_part_t( context_t ctx )
  		:	so_5::agent_t( std::move(ctx) )
  	{}
  
  	virtual void
  	so_define_agent() override
  	{
  		this >>= st_test;
  
  		st_test.event( [this](mhood_t<finish>) {
  				so_deregister_agent_coop_normally();
  			} );
  	}
  };
  
  template< typename Mbox_Case, typename Msg_Type >
  class template_basic_part_t : public nontemplate_basic_part_t
  {
  protected:
  	const Mbox_Case m_mbox_holder;
  
  	virtual void
  	do_next_step() override
  	{
  		so_drop_subscription_for_all_states< Msg_Type >( m_mbox_holder.mbox() );
  
  		so_5::send< Msg_Type >( *this );
  	}
  
  public:
  	template_basic_part_t( context_t ctx )
  		:	nontemplate_basic_part_t( std::move(ctx) )
  		,	m_mbox_holder( *self_ptr() )
  	{}
  
  	virtual void
  	so_evt_start() override
  	{
  		so_5::send<Msg_Type>( m_mbox_holder.mbox() );
  	}
  };
  
  template< typename Mbox_Case, typename Msg_Type >
  class pfn_test_case_t final : public template_basic_part_t< Mbox_Case, Msg_Type >
  {
  	using base_type_t = template_basic_part_t< Mbox_Case, Msg_Type >;
  
  public:
  	pfn_test_case_t( typename base_type_t::context_t ctx )
  		: base_type_t( std::move(ctx) ) {}
  
  	virtual void
  	so_define_agent() override
  	{
  		base_type_t::so_define_agent();
  
  		this->so_subscribe_deadletter_handler( this->m_mbox_holder.mbox(),
  				&pfn_test_case_t::on_deadletter );
  	}	
  
  private:
  	void
  	on_deadletter( so_5::mhood_t<Msg_Type> )
  	{
  		this->actual_deadletter_handler();
  	}
  };
  
  template< typename Mbox_Case, typename Msg_Type >
  class lambda_test_case_t final : public template_basic_part_t< Mbox_Case, Msg_Type >
  {
  	using base_type_t = template_basic_part_t< Mbox_Case, Msg_Type >;
  
  public:
  	lambda_test_case_t( typename base_type_t::context_t ctx )
  		: base_type_t( std::move(ctx) ) {}
  
  	virtual void
  	so_define_agent() override
  	{
  		base_type_t::so_define_agent();
  
  		this->so_subscribe_deadletter_handler( this->m_mbox_holder.mbox(),
  				[this](so_5::mhood_t<Msg_Type>) {
  					this->actual_deadletter_handler();
  				} );
  	}
  };
  
  int
  main()
  {
  	try
  	{
  		run_with_time_limit(
  			[]()
  			{
  				so_5::launch( [&]( so_5::environment_t & env ) {
  						introduce_test_agent<
  								direct_mbox_case_t,
  								test_message,
  								pfn_test_case_t >( env );
  						introduce_test_agent<
  								direct_mbox_case_t,
  								so_5::mutable_msg<test_message>,
  								pfn_test_case_t >( env );
  						introduce_test_agent<
  								direct_mbox_case_t,
  								test_signal,
  								pfn_test_case_t >( env );
  						introduce_test_agent<
  								mpmc_mbox_case_t,
  								test_message,
  								pfn_test_case_t >( env );
  						introduce_test_agent<
  								mpmc_mbox_case_t,
  								test_signal,
  								pfn_test_case_t >( env );
  
  						introduce_test_agent<
  								direct_mbox_case_t,
  								test_message,
  								lambda_test_case_t >( env );
  						introduce_test_agent<
  								direct_mbox_case_t,
  								so_5::mutable_msg<test_message>,
  								lambda_test_case_t >( env );
  						introduce_test_agent<
  								direct_mbox_case_t,
  								test_signal,
  								lambda_test_case_t >( env );
  						introduce_test_agent<
  								mpmc_mbox_case_t,
  								test_message,
  								lambda_test_case_t >( env );
  						introduce_test_agent<
  								mpmc_mbox_case_t,
  								test_signal,
  								lambda_test_case_t >( env );
  					} );
  			},
  			20 );
  	}
  	catch( const std::exception & ex )
  	{
  		std::cerr << "Error: " << ex.what() << std::endl;
  		return 2;
  	}
  
  	return 0;
  }
  
  