text: /*
      Copyright (c) 2013-2014 Contributors as noted in the AUTHORS file
  
      This file is part of azmq
  
      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 AZMQ_DETAIL_SEND_OP_HPP_
  #define AZMQ_DETAIL_SEND_OP_HPP_
  #include "../error.hpp"
  #include "../message.hpp"
  #include "socket_ops.hpp"
  #include "reactor_op.hpp"
  
  #ifdef ASIO_STANDALONE
  #include <asio/io_context.hpp>
  #else
  #include <boost/asio/io_context.hpp>
  #endif
  
  #include <zmq.h>
  #include <iterator>
  
  namespace azmq {
  namespace detail {
  
  template<typename ConstBufferSequence>
  class send_buffer_op_base : public reactor_op {
  public:
      send_buffer_op_base(ConstBufferSequence const& buffers,
                          flags_type flags,
                          complete_func_type complete_func)
          : reactor_op(&send_buffer_op_base::do_perform, complete_func)
          , buffers_(buffers)
          , flags_(flags)
          { }
  
      static bool do_perform(reactor_op* base, socket_type & socket) {
          auto o = static_cast<send_buffer_op_base*>(base);
          o->ec_ = asio::error_code();
          o->bytes_transferred_ += socket_ops::send(o->buffers_, socket, o->flags_ | ZMQ_DONTWAIT, o->ec_);
          if (o->ec_) {
              return !o->try_again();
          }
          return true;
      }
  
  private:
      ConstBufferSequence buffers_;
      flags_type flags_;
  };
  
  template<typename ConstBufferSequence,
           typename Handler>
  class send_buffer_op : public send_buffer_op_base<ConstBufferSequence> {
  public:
      send_buffer_op(ConstBufferSequence const& buffers,
                     Handler handler,
                     reactor_op::flags_type flags)
          : send_buffer_op_base<ConstBufferSequence>(buffers, flags,
                                                     &send_buffer_op::do_complete)
          , handler_(std::move(handler))
      { }
  
      static void do_complete(reactor_op* base,
                              const asio::error_code &,
                              size_t) {
          auto o = static_cast<send_buffer_op*>(base);
          auto h = std::move(o->handler_);
          auto ec = o->ec_;
          auto bt = o->bytes_transferred_;
          delete o;
  
          h(ec, bt);
      }
  
  private:
      Handler handler_;
  };
  
  class send_op_base : public reactor_op {
  public:
      send_op_base(message msg,
                   flags_type flags,
                   complete_func_type complete_func)
          : reactor_op(&send_op_base::do_perform, complete_func)
          , msg_(std::move(msg))
          , flags_(flags)
          { }
  
      static bool do_perform(reactor_op* base, socket_type & socket) {
          auto o = static_cast<send_op_base*>(base);
          o->ec_ = asio::error_code();
          o->bytes_transferred_ = socket_ops::send(o->msg_, socket, o->flags_ | ZMQ_DONTWAIT, o->ec_);
  
          if (o->ec_)
              return !o->try_again(); // some other error
          return true;
      };
  
  private:
      message msg_;
      flags_type flags_;
  };
  
  template<typename Handler>
  class send_op : public send_op_base {
  public:
      send_op(message msg,
              Handler handler,
              flags_type flags)
          : send_op_base(std::move(msg), flags, &send_op::do_complete)
          , handler_(std::move(handler))
      { }
  
      static void do_complete(reactor_op* base,
                              const asio::error_code &,
                              size_t) {
          auto o = static_cast<send_op*>(base);
          auto h = std::move(o->handler_);
          auto ec = o->ec_;
          auto bt = o->bytes_transferred_;
          delete o;
          h(ec, bt);
      }
  
  private:
      Handler handler_;
  };
  
  } // namespace detail
  } // namespace azmq
  #endif // AZMQ_DETAIL_SEND_OP_HPP_
  
  
  