// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_FML_CLOSURE_H_
#define FLUTTER_FML_CLOSURE_H_

#include <functional>

#include "flutter/fml/macros.h"

namespace fml {

using closure = std::function<void()>;

//------------------------------------------------------------------------------
/// @brief      Wraps a closure that is invoked in the destructor unless
///             released by the caller.
///
///             This is especially useful in dealing with APIs that return a
///             resource by accepting ownership of a sub-resource and a closure
///             that releases that resource. When such APIs are chained, each
///             link in the chain must check that the next member in the chain
///             has accepted the resource. If not, it must invoke the closure
///             eagerly. Not doing this results in a resource leak in the
///             erroneous case. Using this wrapper, the closure can be released
///             once the next call in the chain has successfully accepted
///             ownership of the resource. If not, the closure gets invoked
///             automatically at the end of the scope. This covers the cases
///             where there are early returns as well.
///
class ScopedCleanupClosure {
 public:
  ScopedCleanupClosure() = default;

  explicit ScopedCleanupClosure(const fml::closure& closure)
      : closure_(closure) {}

  ~ScopedCleanupClosure() {
    if (closure_) {
      closure_();
    }
  }

  fml::closure SetClosure(const fml::closure& closure) {
    auto old_closure = closure_;
    closure_ = closure;
    return old_closure;
  }

  fml::closure Release() {
    fml::closure closure = closure_;
    closure_ = nullptr;
    return closure;
  }

 private:
  fml::closure closure_;

  FML_DISALLOW_COPY_AND_ASSIGN(ScopedCleanupClosure);
};

}  // namespace fml

#endif  // FLUTTER_FML_CLOSURE_H_
