util: unnest nested Options classes

Change-Id: If20eea845d4c9ff2a03e6133f7ba51b579bcc7e9
diff --git a/ndn-cxx/util/dummy-client-face.cpp b/ndn-cxx/util/dummy-client-face.cpp
index b4dc341..8b55f18 100644
--- a/ndn-cxx/util/dummy-client-face.cpp
+++ b/ndn-cxx/util/dummy-client-face.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2023 Regents of the University of California.
+ * Copyright (c) 2013-2024 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -33,8 +33,9 @@
 #include <boost/asio/post.hpp>
 
 namespace ndn {
+namespace {
 
-class DummyClientFace::Transport final : public ndn::Transport
+class DummyTransport final : public ndn::Transport
 {
 public:
   void
@@ -68,9 +69,11 @@
   }
 
 public:
-  signal::Signal<Transport, Block> onSendBlock;
+  signal::Signal<DummyTransport, Block> onSendBlock;
 };
 
+} // namespace
+
 struct DummyClientFace::BroadcastLink
 {
   std::vector<DummyClientFace*> faces;
@@ -82,7 +85,7 @@
 }
 
 DummyClientFace::DummyClientFace(const Options& options)
-  : Face(make_shared<DummyClientFace::Transport>())
+  : Face(make_shared<DummyTransport>())
   , m_internalKeyChain(make_unique<KeyChain>())
   , m_keyChain(*m_internalKeyChain)
 {
@@ -90,14 +93,14 @@
 }
 
 DummyClientFace::DummyClientFace(KeyChain& keyChain, const Options& options)
-  : Face(make_shared<DummyClientFace::Transport>(), keyChain)
+  : Face(make_shared<DummyTransport>(), keyChain)
   , m_keyChain(keyChain)
 {
   this->construct(options);
 }
 
 DummyClientFace::DummyClientFace(boost::asio::io_context& ioCtx, const Options& options)
-  : Face(make_shared<DummyClientFace::Transport>(), ioCtx)
+  : Face(make_shared<DummyTransport>(), ioCtx)
   , m_internalKeyChain(make_unique<KeyChain>())
   , m_keyChain(*m_internalKeyChain)
 {
@@ -105,7 +108,7 @@
 }
 
 DummyClientFace::DummyClientFace(boost::asio::io_context& ioCtx, KeyChain& keyChain, const Options& options)
-  : Face(make_shared<DummyClientFace::Transport>(), ioCtx, keyChain)
+  : Face(make_shared<DummyTransport>(), ioCtx, keyChain)
   , m_keyChain(keyChain)
 {
   this->construct(options);
@@ -119,7 +122,7 @@
 void
 DummyClientFace::construct(const Options& options)
 {
-  static_cast<Transport&>(getTransport()).onSendBlock.connect([this] (Block packet) {
+  static_cast<DummyTransport&>(getTransport()).onSendBlock.connect([this] (Block packet) {
     packet.encode();
     lp::Packet lpPacket(packet);
     auto frag = lpPacket.get<lp::FragmentField>();
@@ -245,7 +248,7 @@
   addFieldFromTag<lp::NextHopFaceIdField, lp::NextHopFaceIdTag>(lpPacket, interest);
   addFieldFromTag<lp::CongestionMarkField, lp::CongestionMarkTag>(lpPacket, interest);
 
-  static_cast<Transport&>(getTransport()).receive(lpPacket.wireEncode());
+  static_cast<DummyTransport&>(getTransport()).receive(lpPacket.wireEncode());
 }
 
 void
@@ -256,7 +259,7 @@
   addFieldFromTag<lp::IncomingFaceIdField, lp::IncomingFaceIdTag>(lpPacket, data);
   addFieldFromTag<lp::CongestionMarkField, lp::CongestionMarkTag>(lpPacket, data);
 
-  static_cast<Transport&>(getTransport()).receive(lpPacket.wireEncode());
+  static_cast<DummyTransport&>(getTransport()).receive(lpPacket.wireEncode());
 }
 
 void
@@ -270,7 +273,7 @@
   addFieldFromTag<lp::IncomingFaceIdField, lp::IncomingFaceIdTag>(lpPacket, nack);
   addFieldFromTag<lp::CongestionMarkField, lp::CongestionMarkTag>(lpPacket, nack);
 
-  static_cast<Transport&>(getTransport()).receive(lpPacket.wireEncode());
+  static_cast<DummyTransport&>(getTransport()).receive(lpPacket.wireEncode());
 }
 
 void
diff --git a/ndn-cxx/util/dummy-client-face.hpp b/ndn-cxx/util/dummy-client-face.hpp
index 35c9acd..2bc1b59 100644
--- a/ndn-cxx/util/dummy-client-face.hpp
+++ b/ndn-cxx/util/dummy-client-face.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2023 Regents of the University of California.
+ * Copyright (c) 2013-2024 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -29,110 +29,103 @@
 namespace ndn {
 
 /**
+ * \brief Options for DummyClientFace.
+ */
+struct DummyClientFaceOptions
+{
+  DummyClientFaceOptions() = default;
+
+  DummyClientFaceOptions(bool enablePacketLogging, bool enableRegistrationReply,
+                         const std::function<void(time::milliseconds)>& processEventsOverride = nullptr)
+    : enablePacketLogging(enablePacketLogging)
+    , enableRegistrationReply(enableRegistrationReply)
+    , processEventsOverride(processEventsOverride)
+  {
+  }
+
+  /// If true, packets sent out of DummyClientFace will be appended to a container.
+  bool enablePacketLogging = true;
+
+  /// If true, prefix registration commands will be automatically replied to with a successful response.
+  bool enableRegistrationReply = false;
+
+  /// FaceId used in prefix registration replies.
+  uint64_t registrationReplyFaceId = 1;
+
+  /// If not empty, `face.processEvents()` will be overridden by this function.
+  std::function<void(time::milliseconds)> processEventsOverride;
+};
+
+/**
  * \brief A client-side face for unit testing.
  */
 class DummyClientFace : public Face
 {
 public:
-  /**
-   * \brief %Options for DummyClientFace.
-   */
-  class Options
-  {
-  public:
-    Options(bool enablePacketLogging, bool enableRegistrationReply,
-            const std::function<void(time::milliseconds)>& processEventsOverride)
-      : enablePacketLogging(enablePacketLogging)
-      , enableRegistrationReply(enableRegistrationReply)
-      , processEventsOverride(processEventsOverride)
-    {
-    }
-
-    Options(bool enablePacketLogging, bool enableRegistrationReply)
-      : Options(enablePacketLogging, enableRegistrationReply, nullptr)
-    {
-    }
-
-    Options()
-      : Options(true, false)
-    {
-    }
-
-  public:
-    /** \brief If true, packets sent out of DummyClientFace will be appended to a container.
-     */
-    bool enablePacketLogging;
-
-    /** \brief If true, prefix registration command will be automatically
-     *         replied with a successful response.
-     */
-    bool enableRegistrationReply;
-
-    /** \brief FaceId used in prefix registration replies.
-     */
-    uint64_t registrationReplyFaceId = 1;
-
-    /** \brief If not empty, `face.processEvents()` will be overridden by this function.
-     */
-    std::function<void(time::milliseconds)> processEventsOverride;
-  };
-
   class AlreadyLinkedError : public Error
   {
   public:
     AlreadyLinkedError();
   };
 
-  /** \brief Create a dummy face with internal I/O context.
+  using Options = DummyClientFaceOptions;
+
+  /**
+   * \brief Create a dummy face with an internal I/O context.
    */
   explicit
-  DummyClientFace(const Options& options = Options());
+  DummyClientFace(const Options& options = {});
 
-  /** \brief Create a dummy face with internal I/O context and the specified KeyChain.
+  /**
+   * \brief Create a dummy face with an internal I/O context and the specified KeyChain.
    */
   explicit
-  DummyClientFace(KeyChain& keyChain, const Options& options = Options());
+  DummyClientFace(KeyChain& keyChain, const Options& options = {});
 
-  /** \brief Create a dummy face with the provided I/O context.
+  /**
+   * \brief Create a dummy face with the provided I/O context.
    */
   explicit
-  DummyClientFace(boost::asio::io_context& ioCtx, const Options& options = Options());
+  DummyClientFace(boost::asio::io_context& ioCtx, const Options& options = {});
 
-  /** \brief Create a dummy face with the provided I/O context and the specified KeyChain.
+  /**
+   * \brief Create a dummy face with the specified I/O context and KeyChain.
    */
-  DummyClientFace(boost::asio::io_context& ioCtx, KeyChain& keyChain,
-                  const Options& options = Options());
+  DummyClientFace(boost::asio::io_context& ioCtx, KeyChain& keyChain, const Options& options = {});
 
   ~DummyClientFace() override;
 
-  /** \brief Cause the Face to receive an Interest packet.
+  /**
+   * \brief Cause the face to receive an Interest packet.
    */
   void
   receive(const Interest& interest);
 
-  /** \brief Cause the Face to receive a Data packet.
+  /**
+   * \brief Cause the face to receive a Data packet.
    */
   void
   receive(const Data& data);
 
-  /** \brief Cause the Face to receive a Nack packet.
+  /**
+   * \brief Cause the face to receive a Nack packet.
    */
   void
   receive(const lp::Nack& nack);
 
-  /** \brief Link another DummyClientFace through a broadcast media.
+  /**
+   * \brief Link another DummyClientFace through a broadcast medium.
    */
   void
   linkTo(DummyClientFace& other);
 
-  /** \brief Unlink the broadcast media if previously linked.
+  /**
+   * \brief Unlink the broadcast medium if previously linked.
    */
   void
   unlink();
 
 private:
-  class Transport;
-
   void
   construct(const Options& options);
 
@@ -149,45 +142,51 @@
   doProcessEvents(time::milliseconds timeout, bool keepRunning) override;
 
 public:
-  /** \brief Interests sent out of this DummyClientFace.
+  /**
+   * \brief Interests sent out of this DummyClientFace.
    *
-   *  Sent Interests are appended to this container if options.enablePacketLogger is true.
-   *  User of this class is responsible for cleaning up the container, if necessary.
-   *  After .expressInterest, .processEvents must be called before the Interest would show up here.
+   * Sent Interests are appended to this container if Options::enablePacketLogging is true.
+   * The user of this class is responsible for cleaning up the container, if necessary.
+   *
+   * \note After expressInterest(), processEvents() must be called before the %Interest shows up here.
    */
   std::vector<Interest> sentInterests;
 
-  /** \brief Data sent out of this DummyClientFace.
+  /**
+   * \brief %Data sent out of this DummyClientFace.
    *
-   *  Sent Data are appended to this container if options.enablePacketLogger is true.
-   *  User of this class is responsible for cleaning up the container, if necessary.
-   *  After .put, .processEvents must be called before the Data would show up here.
+   * Sent %Data are appended to this container if Options::enablePacketLogging is true.
+   * The user of this class is responsible for cleaning up the container, if necessary.
+   *
+   * \note After put(), processEvents() must be called before the %Data shows up here.
    */
   std::vector<Data> sentData;
 
-  /** \brief Nacks sent out of this DummyClientFace.
+  /**
+   * \brief Nacks sent out of this DummyClientFace.
    *
-   *  Sent Nacks are appended to this container if options.enablePacketLogger is true.
-   *  User of this class is responsible for cleaning up the container, if necessary.
-   *  After .put, .processEvents must be called before the NACK would show up here.
+   * Sent Nacks are appended to this container if Options::enablePacketLogging is true.
+   * The user of this class is responsible for cleaning up the container, if necessary.
+   *
+   * \note After put(), processEvents() must be called before the %Nack shows up here.
    */
   std::vector<lp::Nack> sentNacks;
 
-  /** \brief Emits whenever an Interest is sent.
-   *
-   *  After .expressInterest, .processEvents must be called before this signal would be emitted.
+  /**
+   * \brief Emitted whenever an %Interest is sent.
+   * \note After expressInterest(), processEvents() must be called before this signal is emitted.
    */
   signal::Signal<DummyClientFace, Interest> onSendInterest;
 
-  /** \brief Emits whenever a Data packet is sent.
-   *
-   *  After .put, .processEvents must be called before this signal would be emitted.
+  /**
+   * \brief Emitted whenever a %Data packet is sent.
+   * \note After put(), processEvents() must be called before this signal is emitted.
    */
   signal::Signal<DummyClientFace, Data> onSendData;
 
-  /** \brief Emits whenever a Nack is sent.
-   *
-   *  After .put, .processEvents must be called before this signal would be emitted.
+  /**
+   * \brief Emitted whenever a %Nack is sent.
+   * \note After put(), processEvents() must be called before this signal is emitted.
    */
   signal::Signal<DummyClientFace, lp::Nack> onSendNack;
 
diff --git a/ndn-cxx/util/segment-fetcher.hpp b/ndn-cxx/util/segment-fetcher.hpp
index 1312de6..2635d3e 100644
--- a/ndn-cxx/util/segment-fetcher.hpp
+++ b/ndn-cxx/util/segment-fetcher.hpp
@@ -34,6 +34,46 @@
 namespace ndn {
 
 /**
+ * \brief Options for SegmentFetcher.
+ */
+struct SegmentFetcherOptions
+{
+  /// Lifetime of sent Interests (independent of Interest timeout)
+  time::milliseconds interestLifetime = 4_s;
+  /// Maximum allowed time between successful receipt of segments
+  time::milliseconds maxTimeout = 60_s;
+  /// Use the first Interest to probe the latest version of the object
+  bool probeLatestVersion = true;
+  /// Set to true for 'in order' mode, false for 'block' mode
+  bool inOrder = false;
+  /// If true, Interest timeout is kept fixed at #maxTimeout
+  bool useConstantInterestTimeout = false;
+  /// If true, window size is kept fixed at #initCwnd
+  bool useConstantCwnd = false;
+  /// Disable Conservative Window Adaptation
+  bool disableCwa = false;
+  /// Reduce cwnd to #initCwnd when a loss event occurs
+  bool resetCwndToInit = false;
+  /// Disable window decrease after a congestion mark is received
+  bool ignoreCongMarks = false;
+  /// Initial congestion window size
+  double initCwnd = 1.0;
+  /// Initial slow start threshold
+  double initSsthresh = std::numeric_limits<double>::max();
+  /// Additive increase step (in segments)
+  double aiStep = 1.0;
+  /// Multiplicative decrease coefficient
+  double mdCoef = 0.5;
+  /// Options for the RTT estimator
+  util::RttEstimator::Options rttOptions;
+  /// Maximum number of segments stored in the reorder buffer
+  size_t flowControlWindow = 25000;
+
+  void
+  validate();
+};
+
+/**
  * @brief Utility class to fetch a versioned and segmented object.
  *
  * SegmentFetcher assumes that segments in the object are named `/<prefix>/<version>/<segment>`,
@@ -102,33 +142,7 @@
     FINALBLOCKID_NOT_SEGMENT = 5,
   };
 
-  class Options
-  {
-  public:
-    Options()
-    {
-    }
-
-    void
-    validate();
-
-  public:
-    time::milliseconds interestLifetime = 4_s; ///< lifetime of sent Interests - independent of Interest timeout
-    time::milliseconds maxTimeout = 60_s; ///< maximum allowed time between successful receipt of segments
-    bool probeLatestVersion = true; ///< use the first Interest to probe the latest version of the object
-    bool inOrder = false; ///< true for 'in order' mode, false for 'block' mode
-    bool useConstantInterestTimeout = false; ///< if true, Interest timeout is kept at `maxTimeout`
-    bool useConstantCwnd = false; ///< if true, window size is kept at `initCwnd`
-    bool disableCwa = false; ///< disable Conservative Window Adaptation
-    bool resetCwndToInit = false; ///< reduce cwnd to initCwnd when loss event occurs
-    bool ignoreCongMarks = false; ///< disable window decrease after congestion mark received
-    double initCwnd = 1.0; ///< initial congestion window size
-    double initSsthresh = std::numeric_limits<double>::max(); ///< initial slow start threshold
-    double aiStep = 1.0; ///< additive increase step (in segments)
-    double mdCoef = 0.5; ///< multiplicative decrease coefficient
-    util::RttEstimator::Options rttOptions; ///< options for RTT estimator
-    size_t flowControlWindow = 25000; ///< maximum number of segments stored in the reorder buffer
-  };
+  using Options = SegmentFetcherOptions;
 
   /**
    * @brief Initiates segment fetching.
@@ -155,10 +169,8 @@
    *                     SegmentFetcher's signals can be connected to.
    */
   static shared_ptr<SegmentFetcher>
-  start(Face& face,
-        const Interest& baseInterest,
-        security::Validator& validator,
-        const Options& options = Options());
+  start(Face& face, const Interest& baseInterest, security::Validator& validator,
+        const Options& options = {});
 
   /**
    * @brief Stops fetching.
diff --git a/tests/unit/util/dummy-client-face.t.cpp b/tests/unit/util/dummy-client-face.t.cpp
index 0eea2e6..a946858 100644
--- a/tests/unit/util/dummy-client-face.t.cpp
+++ b/tests/unit/util/dummy-client-face.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2023 Regents of the University of California.
+ * Copyright (c) 2013-2024 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -93,8 +93,8 @@
 
 BOOST_AUTO_TEST_CASE(BroadcastLink)
 {
-  DummyClientFace face1(m_io, m_keyChain, DummyClientFace::Options{true, true});
-  DummyClientFace face2(m_io, m_keyChain, DummyClientFace::Options{true, true});
+  DummyClientFace face1(m_io, m_keyChain, {true, true});
+  DummyClientFace face2(m_io, m_keyChain, {true, true});
   face1.linkTo(face2);
 
   int nFace1Interest = 0;
@@ -141,14 +141,14 @@
 
 BOOST_AUTO_TEST_CASE(BroadcastLinkDestroy)
 {
-  DummyClientFace face1(m_io, m_keyChain, DummyClientFace::Options{true, true});
-  DummyClientFace face2(m_io, m_keyChain, DummyClientFace::Options{true, true});
+  DummyClientFace face1(m_io, m_keyChain, {true, true});
+  DummyClientFace face2(m_io, m_keyChain, {true, true});
 
   face1.linkTo(face2);
   face2.unlink();
   BOOST_CHECK(face1.m_bcastLink == nullptr);
 
-  DummyClientFace face3(m_io, m_keyChain, DummyClientFace::Options{true, true});
+  DummyClientFace face3(m_io, m_keyChain, {true, true});
   face1.linkTo(face2);
   face3.linkTo(face1);
   face2.unlink();