Create quiche_callbacks.h

quiche_callbacks.h introduces the following type aliases:
  - quiche::UnretainedCallback (alias for absl::FunctionRef)
  - quiche::SingleUseCallback (alias for absl::AnyInvocable with && qualifier)
  - quiche::MultiUseCallback (alias for absl::AnyInvocable with const qualifier)

Those are meant to replace existing usage of std::function in QUICHE.

PiperOrigin-RevId: 536477899
diff --git a/build/source_list.bzl b/build/source_list.bzl
index 70cd31f..fe5dee7 100644
--- a/build/source_list.bzl
+++ b/build/source_list.bzl
@@ -47,6 +47,7 @@
     "common/platform/api/quiche_url_utils.h",
     "common/print_elements.h",
     "common/quiche_buffer_allocator.h",
+    "common/quiche_callbacks.h",
     "common/quiche_circular_deque.h",
     "common/quiche_crypto_logging.h",
     "common/quiche_data_reader.h",
@@ -1046,6 +1047,7 @@
     "common/platform/api/quiche_url_utils_test.cc",
     "common/print_elements_test.cc",
     "common/quiche_buffer_allocator_test.cc",
+    "common/quiche_callbacks_test.cc",
     "common/quiche_circular_deque_test.cc",
     "common/quiche_data_reader_test.cc",
     "common/quiche_data_writer_test.cc",
diff --git a/build/source_list.gni b/build/source_list.gni
index 2cf1a78..5f25812 100644
--- a/build/source_list.gni
+++ b/build/source_list.gni
@@ -47,6 +47,7 @@
     "src/quiche/common/platform/api/quiche_url_utils.h",
     "src/quiche/common/print_elements.h",
     "src/quiche/common/quiche_buffer_allocator.h",
+    "src/quiche/common/quiche_callbacks.h",
     "src/quiche/common/quiche_circular_deque.h",
     "src/quiche/common/quiche_crypto_logging.h",
     "src/quiche/common/quiche_data_reader.h",
@@ -1046,6 +1047,7 @@
     "src/quiche/common/platform/api/quiche_url_utils_test.cc",
     "src/quiche/common/print_elements_test.cc",
     "src/quiche/common/quiche_buffer_allocator_test.cc",
+    "src/quiche/common/quiche_callbacks_test.cc",
     "src/quiche/common/quiche_circular_deque_test.cc",
     "src/quiche/common/quiche_data_reader_test.cc",
     "src/quiche/common/quiche_data_writer_test.cc",
diff --git a/build/source_list.json b/build/source_list.json
index c501c60..ae24505 100644
--- a/build/source_list.json
+++ b/build/source_list.json
@@ -46,6 +46,7 @@
     "quiche/common/platform/api/quiche_url_utils.h",
     "quiche/common/print_elements.h",
     "quiche/common/quiche_buffer_allocator.h",
+    "quiche/common/quiche_callbacks.h",
     "quiche/common/quiche_circular_deque.h",
     "quiche/common/quiche_crypto_logging.h",
     "quiche/common/quiche_data_reader.h",
@@ -1045,6 +1046,7 @@
     "quiche/common/platform/api/quiche_url_utils_test.cc",
     "quiche/common/print_elements_test.cc",
     "quiche/common/quiche_buffer_allocator_test.cc",
+    "quiche/common/quiche_callbacks_test.cc",
     "quiche/common/quiche_circular_deque_test.cc",
     "quiche/common/quiche_data_reader_test.cc",
     "quiche/common/quiche_data_writer_test.cc",
diff --git a/quiche/common/quiche_callbacks.h b/quiche/common/quiche_callbacks.h
new file mode 100644
index 0000000..15eb1a9
--- /dev/null
+++ b/quiche/common/quiche_callbacks.h
@@ -0,0 +1,151 @@
+// Copyright 2023 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// quiche_callbacks.h provides definitions for the callback types used by
+// QUICHE.  Those aliases should be used instead of the function types provided
+// by the standard library (std::function) or Abseil (absl::FunctionRef,
+// absl::AnyInvocable).
+//
+// The aliases defined in this class are:
+//   - quiche::UnretainedCallback
+//   - quiche::SingleUseCallback
+//   - quiche::MultiUseCallback
+// Each is documented below near its definition.
+//
+// As a general principle, there are following ways of constructing a callback:
+//   - Using a lambda expression (preferred)
+//   - Using absl::bind_front
+//   - Passing an already defined local function
+//
+// The following methods, however, should be avoided:
+//   - std::bind (<https://abseil.io/tips/108>)
+//   - Binding or taking a pointer to a function outside of the current module,
+//     especially the methods provided by the C++ standard library
+//     (use lambda instead; see go/totw/133 internally for motivation)
+
+#ifndef QUICHE_COMMON_QUICHE_CALLBACKS_H_
+#define QUICHE_COMMON_QUICHE_CALLBACKS_H_
+
+#include <type_traits>
+
+#include "absl/functional/any_invocable.h"
+#include "absl/functional/function_ref.h"
+#include "quiche/common/platform/api/quiche_export.h"
+
+namespace quiche {
+
+namespace callbacks_internal {
+template <class Sig>
+class QUICHE_EXPORT SignatureChanger {};
+
+template <typename ReturnType, typename... Args>
+class QUICHE_EXPORT SignatureChanger<ReturnType(Args...)> {
+ public:
+  using Rvalue = ReturnType(Args...) &&;
+  using Const = ReturnType(Args...) const;
+};
+}  // namespace callbacks_internal
+
+// UnretainedCallback is the QUICHE alias for absl::FunctionRef.
+//
+// UnretainedCallback should be used when a function needs another function
+// passed into it, but it will not retain any pointers to it long-term.
+//
+// For example, a QuicSession class may have function:
+//   void DoForAllStreams(quiche::UnretainedCallback<void(QuicStream*)>);
+//
+// Then a method could call it like this:
+//   int num_bidi_streams = 0;
+//   DoForAllStreams([&num_bidi_streams](QuicStream* stream) {
+//     if (stream->is_bidirectional()) {
+//       ++num_bidi_streams;
+//     }
+//   });
+//
+// Note that similarly to absl::string_view, FunctionRef/UnretainedCallback does
+// not own the underlying memory.  This means that the code below will not work:
+//
+//   quiche::UnretainedCallback f = [&i]() { ++i; }    // <- INVALID CODE
+//
+// The code above allocates a lambda object that stores a pointer to `i` in it,
+// stores a reference to that object inside `f`, and then immediately frees the
+// lambda object.  Attempting to compile the code above will fail with an error
+// that says "Temporary whose address is used as value of local variable 'f'
+// will be destroyed at the end of the full-expression".
+template <class T>
+using UnretainedCallback = absl::FunctionRef<T>;
+
+// SingleUseCallback<T(...)> is the QUICHE alias for
+// absl::AnyInvocable<T(...) &&>.
+//
+// SingleUseCallback is meant to be used for callbacks that may be called at
+// most once.  For instance, a class may have a method that looks like this:
+//
+//   void SetOnSessionDestroyed(quiche::SingleUseCallback<void()> callback) {
+//     on_session_destroyed_callback_ = std::move(callback);
+//   }
+//
+// Then it can execute the callback like this:
+//
+//   ~Session() {
+//     std::move(on_session_destroyed_callback_ )();
+//   }
+//
+// Note that as with other types of similar nature, calling the callback after
+// it has been moved is undefined behavior (it will result in an
+// ABSL_HARDENING_ASSERT() call).
+template <class T>
+using SingleUseCallback = absl::AnyInvocable<
+    typename callbacks_internal::SignatureChanger<T>::Rvalue>;
+
+static_assert(std::is_same_v<SingleUseCallback<void(int, int &, int &&)>,
+                             absl::AnyInvocable<void(int, int &, int &&) &&>>);
+
+// MultiUseCallback<T(...)> is the QUICHE alias for
+// absl::AnyInvocable<T(...) const>.
+//
+// MultiUseCallback is intended for situations where a callback may be invoked
+// multiple times.  It is probably the closest equivalent to std::function
+// in this file, notable differences being that MultiUseCallback is move-only
+// and immutable (meaning that it cannot have an internal state that mutates; it
+// can still point to things that are mutable).
+template <class T>
+using MultiUseCallback =
+    absl::AnyInvocable<typename callbacks_internal::SignatureChanger<T>::Const>;
+
+static_assert(
+    std::is_same_v<MultiUseCallback<void()>, absl::AnyInvocable<void() const>>);
+
+// Use cases that are intentionally not covered by this header file:
+//
+// (a) Mutable callbacks.
+//
+// In C++, it's possible for a lambda to mutate its own state, e.g.:
+//
+//   absl::AnyInvocable<void()> inc = [i = 0]() mutable {
+//     std::cout << (i++) << std::endl;
+//   };
+//   inc();
+//   inc();
+//   inc();
+//
+// The code above will output numbers 0, 1, 2.  The fact that a callback can
+// mutate its internal representation is counterintuitive, and thus not
+// supported. Note that this limitation can be trivially worked around by
+// passing a pointer (e.g., in the example below, `i = 0` could be replaced with
+// `i = std::make_unique<int>(0)` to the similar effect).
+//
+// (b) Copyable callbacks.
+//
+// In C++, this would typically achieved by using std::function.  This file
+// could contain an alias for std::function; it currently does not, since this
+// use case is expected to be fairly rare.
+//
+// (c) noexpect support.
+//
+// We do not use C++ exceptions in QUICHE.
+
+}  // namespace quiche
+
+#endif  // QUICHE_COMMON_QUICHE_CALLBACKS_H_
diff --git a/quiche/common/quiche_callbacks_test.cc b/quiche/common/quiche_callbacks_test.cc
new file mode 100644
index 0000000..4d83d35
--- /dev/null
+++ b/quiche/common/quiche_callbacks_test.cc
@@ -0,0 +1,82 @@
+#include "quiche/common/quiche_callbacks.h"
+
+#include <memory>
+
+#include "quiche/common/platform/api/quiche_test.h"
+
+namespace quiche {
+namespace {
+
+void Apply(const std::vector<int>& container,
+           UnretainedCallback<void(int)> function) {
+  for (int n : container) {
+    function(n);
+  }
+}
+
+TEST(QuicheCallbacksTest, UnretainedCallback) {
+  std::vector<int> nums = {1, 2, 3, 4};
+  int sum = 0;
+  Apply(nums, [&sum](int n) { sum += n; });
+  EXPECT_EQ(sum, 10);
+}
+
+TEST(QuicheCallbacksTest, SingleUseCallback) {
+  int called = 0;
+  SingleUseCallback<void()> callback = [&called]() { called++; };
+  EXPECT_EQ(called, 0);
+
+  SingleUseCallback<void()> new_callback = std::move(callback);
+  EXPECT_EQ(called, 0);
+
+  std::move(new_callback)();
+  EXPECT_EQ(called, 1);
+  EXPECT_QUICHE_DEBUG_DEATH(
+      std::move(new_callback)(),  // NOLINT(bugprone-use-after-move)
+      "AnyInvocable");
+}
+
+class SetFlagOnDestruction {
+ public:
+  SetFlagOnDestruction(bool* flag) : flag_(flag) {}
+  ~SetFlagOnDestruction() { *flag_ = true; }
+
+ private:
+  bool* flag_;
+};
+
+TEST(QuicheCallbacksTest, SingleUseCallbackOwnership) {
+  bool deleted = false;
+  auto flag_setter = std::make_unique<SetFlagOnDestruction>(&deleted);
+  {
+    SingleUseCallback<void()> callback = [setter = std::move(flag_setter)]() {};
+    EXPECT_FALSE(deleted);
+  }
+  EXPECT_TRUE(deleted);
+}
+
+TEST(QuicheCallbacksTest, MultiUseCallback) {
+  int called = 0;
+  MultiUseCallback<void()> callback = [&called]() { called++; };
+  EXPECT_EQ(called, 0);
+
+  callback();
+  EXPECT_EQ(called, 1);
+
+  callback();
+  callback();
+  EXPECT_EQ(called, 3);
+}
+
+TEST(QuicheCallbacksTest, MultiUseCallbackOwnership) {
+  bool deleted = false;
+  auto flag_setter = std::make_unique<SetFlagOnDestruction>(&deleted);
+  {
+    MultiUseCallback<void()> callback = [setter = std::move(flag_setter)]() {};
+    EXPECT_FALSE(deleted);
+  }
+  EXPECT_TRUE(deleted);
+}
+
+}  // namespace
+}  // namespace quiche