/**
 *  Convenience macros for creating sequences.
 *
 *  For example, given:
 *
 *  MAKE_SEQUENCE_FOR_2( APRPoolCreate
 *                     , apr_status_t
 *                     , apr_pool_create
 *                     , apr_pool_t**, new_pool
 *                     , apr_pool_t*, parent_pool
 *                     , apr_pool_t
 *                     , int )
 *
 *  The result is:
 *
 *    struct APRPoolCreateArgs { apr_pool_t** new_pool; apr_pool_t* parent_pool; };
 *
 *    typedef Returner APRPoolCreateReturner;
 *    typedef CallSequence APRPoolCreateSequence;
 *
 *    struct APRPoolCreateFunction {
 *      apr_status_t operator()(apr_pool_t** new_pool, apr_pool_t* parent_pool) {
 *                            return apr_pool_create(new_pool, parent_pool);
 *                          }
 *    };
 *
 *    extern "C" {
 *      apr_status_t override_apr_pool_create(apr_pool_t** new_pool, apr_pool_t* parent_pool);
 *    }
 *
 *  Importantly, you _must_ still do the actual override
 *  #define yourself due to CPP limitations. And, naturally,
 *  define the function itself in the .cpp. The defines
 *  _must_ come after the macro because otherwise you will
 *  override the function there as well (remember to use
 *  extern "C".) So:
 *
 *  // .hpp
 *
 *    MAKE_SEQUENCE_FOR_2(...)
 *
 *    #undef apr_pool_create
 *    #define apr_pool_create(a, b) override_apr_pool_create((a), (b))
 *
 *  // .cpp
 *
 *    extern "C" {
 *      
 *    }
 */

/*
 * So if I make the sequence for recv(), I can then do a few things
 * depending on what the override function itself does. For example,
 * here is the basic version:
 */

  int override_recv(int fd, void* buffer, std::size_t length, int options)
  {
    RecvArgs r = { fd, buffer, length, options };
    const RecvSequence::ReturnType& ret = RecvSequence::called_with(r);

    if(  ret.return_value() == -1  ) {
      // Set errno to allow testing EINTR etc. if requested
      if(  ret.error_number() > 0  ) {
        errno = ret.error_number();
      }
    }
    // Fake the write to the buffer if data given
    else if (  ret.payload()  ) {
      ret.payload()->copy(static_cast(buffer), ret.return_value());
    }

    return ret.return_value();
  }

/* 
 * So as you see, we can simulate error conditions, optionally set
 * errno using the info from the Returner instantiation instance.
 * OR we can fake a successful call which optionally allows returning
 * some predefined "data" for the caller of recv() to use. The Returners
 * are set up by defining a _sequence_ of returns (which may be zero
 * or more returns, the count is also checked.)
 *
 * For example:
 */

// Simulate single failed read
RecvSequence::clear();
RecvSequence::next_return_sequence_is(-1, ECONNRESET);  // Implicit coercion

// Simulate two partial reads and then EOS
RecvSequence::clear();
std::string foo("Hello ");
std::string bar("world\n");
RecvSequence::next_return_sequence_is( RecvReturner(foo.length(), &foo)
                                     , RecvReturner(bar.length(), &bar)
                                     , RecvReturner(0) );