diff --git a/STYLE.md b/STYLE.md index 1a3ad8358..0dfa46741 100644 --- a/STYLE.md +++ b/STYLE.md @@ -60,3 +60,9 @@ footguns, crashes, bugs, and UB. * But don't follow the IWYU rules _inside_ the library. We include the minimal internal headers internally to reduce the amount of textual parsing needed to satisfy including one public header. +1. All types in requires clauses should be references or pointers. + * For mutable access always write it as `requires(T& t)` instead of + `requires (T t)`, as the latter will not match pure virtual types in + clang-16. + * Similarly, for const usage, write `requires (const T& t)` instead of + `requires (const T t)`. diff --git a/subdoc/gen_tests/markdown/Syntax.html b/subdoc/gen_tests/markdown/Syntax.html new file mode 100644 index 000000000..7aabe2982 --- /dev/null +++ b/subdoc/gen_tests/markdown/Syntax.html @@ -0,0 +1,82 @@ + + + + + + + + Syntax - PROJECT NAME + + + + + + + + + + + + +
+
+
+
+ + Struct + + PROJECT NAME + :: + Syntax +
+
+ + struct + + + Syntax + +
+ { ... }; +
+
+
+

A code block with syntax highlighting.

+
A comment;  // At the end of the line.
+// At the start of the line.
+  // And after some whitespace.
+
+ +
+
+
+
+ diff --git a/subdoc/gen_tests/markdown/index.html b/subdoc/gen_tests/markdown/index.html index cf65fd554..e7d7f0e57 100644 --- a/subdoc/gen_tests/markdown/index.html +++ b/subdoc/gen_tests/markdown/index.html @@ -52,6 +52,9 @@
  • S
  • +
  • + Syntax +
  • @@ -91,6 +94,16 @@

    The summary has html tags in it.

    +
  • +
    +
    + Syntax +
    +
    +
    +

    A code block with syntax highlighting.

    +
    +
  • diff --git a/subdoc/gen_tests/markdown/test.cc b/subdoc/gen_tests/markdown/test.cc index 549f3e47c..c16505663 100644 --- a/subdoc/gen_tests/markdown/test.cc +++ b/subdoc/gen_tests/markdown/test.cc @@ -8,3 +8,11 @@ struct S {}; /// newlines in /// it. struct N {}; + +/// A code block with syntax highlighting. +/// ``` +/// A comment; // At the end of the line. +/// // At the start of the line. +/// // And after some whitespace. +/// ``` +struct Syntax {}; diff --git a/subdoc/gen_tests/struct-complex/S.html b/subdoc/gen_tests/struct-complex/S.html index f1b8690d5..ccbbd8fc2 100644 --- a/subdoc/gen_tests/struct-complex/S.html +++ b/subdoc/gen_tests/struct-complex/S.html @@ -73,6 +73,12 @@
  • void_method
  • +
  • + Operators +
  • +
  • + operator() +
  • Data Members
  • @@ -190,6 +196,28 @@ +
    +
    + Operators +
    +
    +
    +
    +
    auto operator()() const& -> int
    +
    +
    +
    auto operator()() & -> bool
    +
    +
    +
    auto operator()() && -> float
    +
    +
    +
    +

    Call operator with two overloads.

    + +
    +
    +
    Data Members diff --git a/subdoc/gen_tests/struct-complex/test.cc b/subdoc/gen_tests/struct-complex/test.cc index 55a61e2fe..e27b5ee25 100644 --- a/subdoc/gen_tests/struct-complex/test.cc +++ b/subdoc/gen_tests/struct-complex/test.cc @@ -6,16 +6,16 @@ struct OtherType {}; /// Comment headline S struct S { /// Comment headline void_method - void void_method() const& {} + void void_method() const&; /// Comment headline static_type_method - static OtherType static_type_method() {} + static OtherType static_type_method(); /// Comment headline type_method - OtherType type_method() {} + OtherType type_method(); /// Comment headline static_bool_method - static bool static_bool_method() {} + static bool static_bool_method(); // Overload should be grouped with the other int_method(). - void int_method() volatile {} + void int_method() volatile; /// Comment headline type_field const OtherType type_field; @@ -25,4 +25,9 @@ struct S { bool bool_field; /// Comment headline static_bool_member static bool static_bool_member; + + /// Call operator with two overloads. + int operator()() const&; + bool operator()() &; + float operator()() &&; }; diff --git a/subdoc/gen_tests/subdoc-test-style.css b/subdoc/gen_tests/subdoc-test-style.css index 34a3c2575..6687ced58 100644 --- a/subdoc/gen_tests/subdoc-test-style.css +++ b/subdoc/gen_tests/subdoc-test-style.css @@ -206,6 +206,9 @@ main { color:rgb(230, 230, 230); overflow-x: auto; } +pre > code span.comment { + color: #3ff9bd; +} .section-header { font-size: 125%; diff --git a/subdoc/lib/database.h b/subdoc/lib/database.h index 287f8ca05..a8b2018ee 100644 --- a/subdoc/lib/database.h +++ b/subdoc/lib/database.h @@ -18,13 +18,13 @@ #include "subdoc/lib/doc_attributes.h" #include "subdoc/lib/friendly_names.h" +#include "subdoc/lib/linked_type.h" #include "subdoc/lib/method_qualifier.h" #include "subdoc/lib/parse_comment.h" #include "subdoc/lib/path.h" #include "subdoc/lib/record_type.h" #include "subdoc/lib/requires.h" #include "subdoc/lib/type.h" -#include "subdoc/lib/linked_type.h" #include "subdoc/lib/unique_symbol.h" #include "subdoc/llvm.h" #include "sus/assertions/check.h" @@ -226,7 +226,7 @@ struct FunctionElement : public CommentElement { return sus::none(); } - void for_each_comment(sus::fn::FnMutRef fn) { fn(comment); } + void for_each_comment(sus::fn::FnMut auto fn) { fn(comment); } }; struct ConceptElement : public CommentElement { @@ -262,7 +262,7 @@ struct ConceptElement : public CommentElement { return sus::none(); } - void for_each_comment(sus::fn::FnMutRef fn) { fn(comment); } + void for_each_comment(sus::fn::FnMut auto fn) { fn(comment); } }; struct FieldElement : public CommentElement { @@ -310,7 +310,7 @@ struct FieldElement : public CommentElement { return sus::none(); } - void for_each_comment(sus::fn::FnMutRef fn) { fn(comment); } + void for_each_comment(sus::fn::FnMut auto fn) { fn(comment); } }; struct ConceptId { @@ -552,7 +552,7 @@ struct RecordElement : public TypeElement { return out; } - void for_each_comment(sus::fn::FnMutRef fn) { + void for_each_comment(sus::fn::FnMut auto fn) { fn(comment); for (auto& [k, e] : records) e.for_each_comment(fn); for (auto& [k, e] : fields) e.for_each_comment(fn); @@ -736,7 +736,7 @@ struct NamespaceElement : public CommentElement { return out; } - void for_each_comment(sus::fn::FnMutRef fn) { + void for_each_comment(sus::fn::FnMut auto fn) { fn(comment); for (auto& [k, e] : concepts) e.for_each_comment(fn); for (auto& [k, e] : namespaces) e.for_each_comment(fn); @@ -777,13 +777,11 @@ struct Database { sus::Vec to_resolve; { sus::Vec* to_resolve_ptr = &to_resolve; - sus::fn::FnMutBox fn = sus_bind_mut( - sus_store(sus_unsafe_pointer(to_resolve_ptr)), [&](Comment& c) { - if (c.attrs.inherit.is_some()) { - to_resolve_ptr->push(&c); - } - }); - global.for_each_comment(fn); + global.for_each_comment([&](Comment& c) { + if (c.attrs.inherit.is_some()) { + to_resolve_ptr->push(&c); + } + }); } while (!to_resolve.is_empty()) { @@ -931,41 +929,44 @@ struct Database { sus::Vec> collect_type_element_refs( const Type& type) const noexcept { sus::Vec> vec; - type_walk_types(type, [&](TypeToStringQuery q) { - const NamespaceElement* ns_cursor = &global; - for (const std::string& name : q.namespace_path) { - auto it = ns_cursor->namespaces.find(NamespaceId(name)); - if (it == ns_cursor->namespaces.end()) { - vec.push(sus::none()); - return; - } - ns_cursor = &it->second; - } - if (q.record_path.is_empty()) { - vec.push(ns_cursor->get_local_type_element_ref_by_name(q.name)); - return; - } + type_walk_types( + type, + sus::dyn>( + [&](TypeToStringQuery q) { + const NamespaceElement* ns_cursor = &global; + for (const std::string& name : q.namespace_path) { + auto it = ns_cursor->namespaces.find(NamespaceId(name)); + if (it == ns_cursor->namespaces.end()) { + vec.push(sus::none()); + return; + } + ns_cursor = &it->second; + } + if (q.record_path.is_empty()) { + vec.push(ns_cursor->get_local_type_element_ref_by_name(q.name)); + return; + } - const RecordElement* rec_cursor = nullptr; - for (const auto& [i, name] : q.record_path.iter().enumerate()) { - if (i == 0u) { - auto it = ns_cursor->records.find(RecordId(name)); - if (it == ns_cursor->records.end()) { - vec.push(sus::none()); - return; - } - rec_cursor = &it->second; - } else { - auto it = rec_cursor->records.find(RecordId(name)); - if (it == rec_cursor->records.end()) { - vec.push(sus::none()); - return; - } - rec_cursor = &it->second; - } - } - vec.push(rec_cursor->get_local_type_element_ref_by_name(q.name)); - }); + const RecordElement* rec_cursor = nullptr; + for (const auto& [i, name] : q.record_path.iter().enumerate()) { + if (i == 0u) { + auto it = ns_cursor->records.find(RecordId(name)); + if (it == ns_cursor->records.end()) { + vec.push(sus::none()); + return; + } + rec_cursor = &it->second; + } else { + auto it = rec_cursor->records.find(RecordId(name)); + if (it == rec_cursor->records.end()) { + vec.push(sus::none()); + return; + } + rec_cursor = &it->second; + } + } + vec.push(rec_cursor->get_local_type_element_ref_by_name(q.name)); + })); return vec; } diff --git a/subdoc/lib/gen/generate_function.cc b/subdoc/lib/gen/generate_function.cc index 567918ccc..04be79c39 100644 --- a/subdoc/lib/gen/generate_function.cc +++ b/subdoc/lib/gen/generate_function.cc @@ -49,9 +49,12 @@ void generate_function_params(HtmlWriter::OpenDiv& div, if (p.parameter_name.empty()) { generate_type(div, p.type, sus::none()); } else { - generate_type(div, p.type, sus::some([&](HtmlWriter::OpenDiv& div) { - div.write_text(p.parameter_name); - })); + generate_type( + div, p.type, + sus::some(sus::dyn>( + [&](HtmlWriter::OpenDiv& div) { + div.write_text(p.parameter_name); + }))); } if (p.default_value.is_some()) { diff --git a/subdoc/lib/gen/generate_record.cc b/subdoc/lib/gen/generate_record.cc index b3399cc42..d44d92d64 100644 --- a/subdoc/lib/gen/generate_record.cc +++ b/subdoc/lib/gen/generate_record.cc @@ -243,13 +243,15 @@ sus::Result generate_record_fields( } name_div.write_text(" "); } - generate_type(name_div, fe.type, - sus::some([&](HtmlWriter::OpenDiv& div) { - auto anchor = div.open_a(); - anchor.add_href(construct_html_url_for_field(fe)); - anchor.add_class("field-name"); - anchor.write_text(fe.name); - })); + generate_type( + name_div, fe.type, + sus::some(sus::dyn>( + [&](HtmlWriter::OpenDiv& div) { + auto anchor = div.open_a(); + anchor.add_href(construct_html_url_for_field(fe)); + anchor.add_class("field-name"); + anchor.write_text(fe.name); + }))); } { auto desc_div = field_div.open_div(); diff --git a/subdoc/lib/gen/generate_type.cc b/subdoc/lib/gen/generate_type.cc index 5be1b2c0c..21da172d0 100644 --- a/subdoc/lib/gen/generate_type.cc +++ b/subdoc/lib/gen/generate_type.cc @@ -34,7 +34,7 @@ std::string make_title_string(TypeToStringQuery q) { } // namespace void generate_type(HtmlWriter::OpenDiv& div, const LinkedType& linked_type, - sus::Option> + sus::Option&> var_name_fn) noexcept { auto text_fn = [&](std::string_view text) { div.write_text(text); }; auto type_fn = [&, i_ = 0_usize](TypeToStringQuery q) mutable { @@ -79,15 +79,17 @@ void generate_type(HtmlWriter::OpenDiv& div, const LinkedType& linked_type, span.write_text("volatile"); }; auto var_fn = [&]() { sus::move(var_name_fn).unwrap()(div); }; + // Construct our DynFnMut reference to `var_fn` in case we need it so that + // it can outlive the Option holding a ref to it. + auto dyn_fn = sus::dyn>(var_fn); + auto opt_dyn_fn = sus::Option&>(dyn_fn); - type_to_string(linked_type.type, text_fn, type_fn, const_fn, volatile_fn, - [&]() -> sus::Option> { - if (var_name_fn.is_some()) { - return sus::some(sus::move(var_fn)); - } else { - return sus::none(); - } - }()); + type_to_string(linked_type.type, + sus::dyn>(text_fn), + sus::dyn>(type_fn), + sus::dyn>(const_fn), + sus::dyn>(volatile_fn), + var_name_fn.and_that(sus::move(opt_dyn_fn))); } } // namespace subdoc::gen diff --git a/subdoc/lib/gen/generate_type.h b/subdoc/lib/gen/generate_type.h index 36a3085a3..086d6c12a 100644 --- a/subdoc/lib/gen/generate_type.h +++ b/subdoc/lib/gen/generate_type.h @@ -17,13 +17,13 @@ #include "subdoc/lib/database.h" #include "subdoc/lib/gen/html_writer.h" #include "subdoc/lib/type.h" +#include "sus/fn/fn.h" #include "sus/prelude.h" -#include "sus/fn/fn_ref.h" namespace subdoc::gen { -void generate_type( - HtmlWriter::OpenDiv& div, const LinkedType& linked_type, - sus::Option> var_name_fn) noexcept; +void generate_type(HtmlWriter::OpenDiv& div, const LinkedType& linked_type, + sus::Option&> + var_name_fn) noexcept; } // namespace subdoc::gen diff --git a/subdoc/lib/gen/markdown_to_html.cc b/subdoc/lib/gen/markdown_to_html.cc index 4f5c7ce8a..32ed410c7 100644 --- a/subdoc/lib/gen/markdown_to_html.cc +++ b/subdoc/lib/gen/markdown_to_html.cc @@ -256,6 +256,40 @@ sus::Result markdown_to_html( } } std::string str = sus::move(parsed).str(); + usize pos; + while (true) { + pos = str.find("
    ", pos);
    +    if (pos == std::string::npos) break;
    +    usize end_pos = str.find("
    ", pos + 5u); + if (end_pos == std::string::npos) break; + + while (true) { + usize comment_pos = str.find("// ", pos); + if (comment_pos == std::string::npos) { + pos = str.size(); + break; + } + if (comment_pos >= end_pos) { + // If we went past then back up and look for the next
    .
    +        pos = end_pos + 6u;
    +        break;
    +      }
    +
    +      const std::string_view open = "";
    +      const std::string_view close = "";
    +
    +      str.insert(comment_pos, open);
    +      comment_pos += open.size();
    +      end_pos += open.size();
    +
    +      usize eol_pos = str.find("\n", comment_pos);
    +      if (eol_pos == std::string::npos) eol_pos = str.size();
    +      str.insert(eol_pos, close);
    +      eol_pos += close.size();
    +      end_pos += close.size();
    +      pos = eol_pos;
    +    }
    +  }
       return sus::ok(MarkdownToHtml{
           .full_html = sus::clone(str),
           .summary_html = summarize_html(str),
    diff --git a/subdoc/lib/run_options.h b/subdoc/lib/run_options.h
    index ee7f03388..9940eca22 100644
    --- a/subdoc/lib/run_options.h
    +++ b/subdoc/lib/run_options.h
    @@ -17,6 +17,7 @@
     #include 
     
     #include "subdoc/llvm.h"
    +#include "sus/boxed/box.h"
     #include "sus/fn/fn.h"
     #include "sus/option/option.h"
     #include "sus/prelude.h"
    @@ -39,7 +40,8 @@ struct RunOptions {
         return sus::move(*this);
       }
       RunOptions set_on_tu_complete(
    -      sus::fn::FnBox fn) && {
    +      sus::Box>
    +          fn) && {
         on_tu_complete = sus::some(sus::move(fn));
         return sus::move(*this);
       }
    @@ -54,7 +56,8 @@ struct RunOptions {
       ///
       /// Used for tests to observe the AST and test subdoc methods that act on
       /// things from the AST.
    -  sus::Option>
    +  sus::Option<
    +      sus::Box>>
           on_tu_complete;
       /// The overview markdown which will be applied as the doc comment to the
       /// global namespace/project overview page. This is the raw markdown text, not
    diff --git a/subdoc/lib/type.cc b/subdoc/lib/type.cc
    index 361d9fa26..9a95dcfcb 100644
    --- a/subdoc/lib/type.cc
    +++ b/subdoc/lib/type.cc
    @@ -528,11 +528,11 @@ Type build_local_type(clang::QualType qualtype, const clang::SourceManager& sm,
     namespace {
     
     void type_to_string_internal(
    -    const Type& type, sus::fn::FnMutRef& text_fn,
    -    sus::fn::FnMutRef& type_fn,
    -    sus::fn::FnMutRef& const_qualifier_fn,
    -    sus::fn::FnMutRef& volatile_qualifier_fn,
    -    sus::Option> var_name_fn) noexcept {
    +    const Type& type, sus::fn::DynFnMut& text_fn,
    +    sus::fn::DynFnMut& type_fn,
    +    sus::fn::DynFnMut& const_qualifier_fn,
    +    sus::fn::DynFnMut& volatile_qualifier_fn,
    +    sus::Option&> var_name_fn) noexcept {
       if (type.qualifier.is_const) {
         const_qualifier_fn();
         text_fn(" ");
    @@ -681,7 +681,7 @@ void type_to_string_internal(
     
     void type_walk_types_internal(
         const Type& type,
    -    sus::fn::FnMutRef& type_fn) noexcept {
    +    sus::fn::DynFnMut& type_fn) noexcept {
       for (const TypeOrValue& tv : type.nested_names) {
         switch (tv.choice) {
           case TypeOrValueTag::Type: {
    @@ -730,18 +730,18 @@ void type_walk_types_internal(
     }  // namespace
     
     void type_to_string(
    -    const Type& type, sus::fn::FnMutRef text_fn,
    -    sus::fn::FnMutRef type_fn,
    -    sus::fn::FnMutRef const_qualifier_fn,
    -    sus::fn::FnMutRef volatile_qualifier_fn,
    -    sus::Option> var_name_fn) noexcept {
    +    const Type& type, sus::fn::DynFnMut& text_fn,
    +    sus::fn::DynFnMut& type_fn,
    +    sus::fn::DynFnMut& const_qualifier_fn,
    +    sus::fn::DynFnMut& volatile_qualifier_fn,
    +    sus::Option&> var_name_fn) noexcept {
       return type_to_string_internal(type, text_fn, type_fn, const_qualifier_fn,
                                      volatile_qualifier_fn, sus::move(var_name_fn));
     }
     
     void type_walk_types(
         const Type& type,
    -    sus::fn::FnMutRef type_fn) noexcept {
    +    sus::fn::DynFnMut& type_fn) noexcept {
       return type_walk_types_internal(type, type_fn);
     }
     
    diff --git a/subdoc/lib/type.h b/subdoc/lib/type.h
    index 3431ebc23..9610c016d 100644
    --- a/subdoc/lib/type.h
    +++ b/subdoc/lib/type.h
    @@ -17,7 +17,7 @@
     #include "subdoc/llvm.h"
     #include "sus/choice/choice.h"
     #include "sus/collections/vec.h"
    -#include "sus/fn/fn_ref.h"
    +#include "sus/fn/fn.h"
     #include "sus/prelude.h"
     
     namespace subdoc {
    @@ -242,16 +242,16 @@ struct TypeToStringQuery {
     /// The `var_name_fn` is called at the place where the variable name (if any)
     /// would appear.
     void type_to_string(
    -    const Type& type, sus::fn::FnMutRef text_fn,
    -    sus::fn::FnMutRef type_fn,
    -    sus::fn::FnMutRef const_qualifier_fn,
    -    sus::fn::FnMutRef volatile_qualifier_fn,
    -    sus::Option> var_name_fn) noexcept;
    +    const Type& type, sus::fn::DynFnMut& text_fn,
    +    sus::fn::DynFnMut& type_fn,
    +    sus::fn::DynFnMut& const_qualifier_fn,
    +    sus::fn::DynFnMut& volatile_qualifier_fn,
    +    sus::Option&> var_name_fn) noexcept;
     
     /// Like `type_to_string` but just walks through the types and does not produce
     /// any output.
     void type_walk_types(
         const Type& type,
    -    sus::fn::FnMutRef type_fn) noexcept;
    +    sus::fn::DynFnMut& type_fn) noexcept;
     
     }  // namespace subdoc
    diff --git a/subdoc/lib/visit.cc b/subdoc/lib/visit.cc
    index a24da4a88..7eb64b60e 100644
    --- a/subdoc/lib/visit.cc
    +++ b/subdoc/lib/visit.cc
    @@ -517,9 +517,10 @@ class Visitor : public clang::RecursiveASTVisitor {
                         ->getNameAsString();
                   } else if (auto* convdecl =
                                  clang::dyn_cast(decl)) {
    -                Type t = build_local_type(convdecl->getReturnType(),
    -                                          convdecl->getASTContext().getSourceManager(),
    -                                          preprocessor_);
    +                Type t = build_local_type(
    +                    convdecl->getReturnType(),
    +                    convdecl->getASTContext().getSourceManager(),
    +                    preprocessor_);
                     return std::string("operator ") + t.name;
                   } else {
                     return decl->getNameAsString();
    @@ -538,10 +539,27 @@ class Visitor : public clang::RecursiveASTVisitor {
                 sus::Option overload_set =
                     sus::clone(comment.attrs.overload_set);
     
    -            std::string signature;
    +            std::string signature = "(";
                 for (clang::ParmVarDecl* p : decl->parameters()) {
                   signature += p->getOriginalType().getAsString();
                 }
    +            signature += ")";
    +            if (auto* mdecl = clang::dyn_cast(decl)) {
    +              // Prevent a parameter and return qualifier from possibly being
    +              // confused for eachother in the string by putting a delimiter in
    +              // here that can't appear in the parameter list.
    +              signature += " -> ";
    +              signature += mdecl->getMethodQualifiers().getAsString();
    +              switch (mdecl->getRefQualifier()) {
    +                case clang::RefQualifierKind::RQ_None: break;
    +                case clang::RefQualifierKind::RQ_LValue:
    +                  signature += "&";
    +                  break;
    +                case clang::RefQualifierKind::RQ_RValue:
    +                  signature += "&&";
    +                  break;
    +              }
    +            }
     
                 auto linked_return_type = LinkedType::with_type(
                     build_local_type(decl->getReturnType(),
    @@ -561,7 +579,7 @@ class Visitor : public clang::RecursiveASTVisitor {
                     decl->getASTContext().getSourceManager().getFileOffset(
                         decl->getLocation()));
     
    -            if (clang::isa(decl)) {
    +            if (auto* mdecl = clang::dyn_cast(decl)) {
                   sus::check(clang::isa(context));
     
                   // TODO: It's possible to overload a method in a base class. What
    @@ -572,7 +590,6 @@ class Visitor : public clang::RecursiveASTVisitor {
                   if (sus::Option parent = docs_db_.find_record_mut(
                           clang::cast(context));
                       parent.is_some()) {
    -                auto* mdecl = clang::cast(decl);
                     fe.overloads[0u].method = sus::some(MethodSpecific{
                         .is_static = mdecl->isStatic(),
                         .is_volatile = mdecl->isVolatile(),
    @@ -644,7 +661,9 @@ class Visitor : public clang::RecursiveASTVisitor {
           // We already visited this thing, from another translation unit.
           add_overload = false;
         } else {
    -      add_overload = true;
    +      // The comment is ambiguous, there's another comment for the same overload
    +      // set. This is an error.
    +      add_overload = false;
           auto& ast_cx = decl->getASTContext();
           const auto& old_comment_element = it->second;
           ast_cx.getDiagnostics()
    diff --git a/subdoc/tests/type_unittest.cc b/subdoc/tests/type_unittest.cc
    index 7b1778701..2fc418d89 100644
    --- a/subdoc/tests/type_unittest.cc
    +++ b/subdoc/tests/type_unittest.cc
    @@ -34,14 +34,18 @@ std::string make_string(std::string_view var_name, const subdoc::Type& type) {
       auto const_fn = [&]() { str << "const"; };
       auto volatile_fn = [&]() { str << "volatile"; };
       auto var_fn = [&]() { str << var_name; };
    -
    -  subdoc::type_to_string(type, text_fn, type_fn, const_fn, volatile_fn,
    -                         [&]() -> sus::Option> {
    -                           if (var_name.empty())
    -                             return sus::none();
    -                           else
    -                             return sus::some(sus::move(var_fn));
    -                         }());
    +  // Construct our DynFnMut reference to `var_fn` in case we need it so that
    +  // it can outlive the Option holding a ref to it.
    +  auto dyn_fn = sus::dyn>(var_fn);
    +  sus::Option&> opt_dyn_fn;
    +  if (!var_name.empty()) opt_dyn_fn.insert(dyn_fn);
    +
    +  subdoc::type_to_string(
    +      type, sus::dyn>(text_fn),
    +      sus::dyn>(type_fn),
    +      sus::dyn>(const_fn),
    +      sus::dyn>(volatile_fn),
    +      sus::move(opt_dyn_fn));
       return sus::move(str).str();
     }
     
    @@ -79,7 +83,7 @@ struct SubDocTypeTest : public SubDocTest {
                                         clang::Preprocessor&)> auto body) {
         auto opts = subdoc::RunOptions()           //
                         .set_show_progress(false)  //
    -                    .set_on_tu_complete(body);
    +                    .set_on_tu_complete(sus::move_into(body));
         auto result = run_code_with_options(opts, code);
         ASSERT_TRUE(result.is_ok());
       }
    diff --git a/sus/CMakeLists.txt b/sus/CMakeLists.txt
    index 9f84a8a60..ac6e5b27d 100644
    --- a/sus/CMakeLists.txt
    +++ b/sus/CMakeLists.txt
    @@ -25,6 +25,7 @@ target_sources(subspace PUBLIC
         "assertions/panic.cc"
         "assertions/unreachable.h"
         "boxed/box.h"
    +    "boxed/dyn.h"
         "choice/__private/all_values_are_unique.h"
         "choice/__private/index_of_value.h"
         "choice/__private/index_type.h"
    @@ -75,16 +76,9 @@ target_sources(subspace PUBLIC
         "env/var.h"
         "error/compat_error.h"
         "error/error.h"
    -    "fn/__private/callable_types.h"
    -    "fn/__private/fn_box_storage.h"
    -    "fn/__private/fn_ref_invoker.h"
         "fn/__private/signature.h"
    -    "fn/callable.h"
         "fn/fn.h"
    -    "fn/bind.h"
    -    "fn/fn_box_defn.h"
    -    "fn/fn_box_impl.h"
    -    "fn/fn_ref.h"
    +    "fn/fn_dyn.h"
         "iter/__private/into_iterator_archetype.h"
         "iter/__private/is_generator.h"
         "iter/__private/iter_compare.h"
    @@ -252,6 +246,7 @@ if(${SUBSPACE_BUILD_TESTS})
             "assertions/panic_unittest.cc"
             "assertions/unreachable_unittest.cc"
             "boxed/box_unittest.cc"
    +        "boxed/dyn_unittest.cc"
             "choice/choice_types_unittest.cc"
             "choice/choice_unittest.cc"
             "construct/transmogrify_unittest.cc"
    @@ -275,9 +270,8 @@ if(${SUBSPACE_BUILD_TESTS})
             "construct/default_unittest.cc"
             "env/var_unittest.cc"
             "error/error_unittest.cc"
    -        "fn/fn_box_unittest.cc"
             "fn/fn_concepts_unittest.cc"
    -        "fn/fn_ref_unittest.cc"
    +        "fn/fn_dyn_unittest.cc"
             "iter/compat_ranges_unittest.cc"
             "iter/empty_unittest.cc"
             "iter/generator_unittest.cc"
    diff --git a/sus/boxed/__private/string_error.h b/sus/boxed/__private/string_error.h
    index 55b19bbd6..7ff6b5c6c 100644
    --- a/sus/boxed/__private/string_error.h
    +++ b/sus/boxed/__private/string_error.h
    @@ -12,6 +12,8 @@
     // See the License for the specific language governing permissions and
     // limitations under the License.
     
    +// IWYU pragma: private
    +// IWYU pragma: friend "sus/.*"
     #pragma once
     
     #include "sus/error/error.h"
    diff --git a/sus/boxed/box.h b/sus/boxed/box.h
    index 9f5d795f0..16e6b001c 100644
    --- a/sus/boxed/box.h
    +++ b/sus/boxed/box.h
    @@ -19,7 +19,10 @@
     #include 
     
     #include "sus/boxed/__private/string_error.h"
    +#include "sus/boxed/boxed.h"  // namespace docs.
     #include "sus/error/error.h"
    +#include "sus/fn/fn_concepts.h"
    +#include "sus/fn/fn_dyn.h"
     #include "sus/macros/no_unique_address.h"
     #include "sus/macros/pure.h"
     #include "sus/mem/clone.h"
    @@ -36,9 +39,80 @@ namespace sus::boxed {
     
     // TODO: Box has an allocator parameter in Rust but std::unique_ptr does not.
     // Which do we do?
    +
    +/// A heap allocated object.
    +///
    +/// A `Box` holds ownership of an object of type `T` on the heap. When `Box`
    +/// is destroyed, or an rvalue-qualified method is called, the inner heap
    +/// object is freed.
    +///
    +/// `Box` is similar to [`std::unique_ptr`](
    +/// https://en.cppreference.com/w/cpp/memory/unique_ptr) with some differences,
    +/// and should be preferred when those differences will benefit you:
    +/// * Const correctness. A `const Box` treats the inner object as `const` and
    +///   does not expose mutable access to it.
    +/// * Never null. A `Box` always holds a value until it is moved-from. It is
    +///   constructed from a value, not a pointer. Alternatively it can be
    +///   constructed from the constructor arguments by
    +///   [`with_args`]($sus::boxed::Box::with_args), like [`std::make_unique`](
    +///   https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique)
    +///   but built into the type.
    +///   A moved-from `Box` may not be used except to be assigned to or destroyed.
    +///   Using a moved-from `Box` will [`panic`]($sus::assertions::panic) and
    +///   terminate the program rather than operate on a null. This prevents
    +///   Undefined Behaviour and memory bugs caused by dereferencing null or using
    +///   null in unintended ways.
    +/// * Supports up-casting (TODO: and [`down-casting`](
    +///   https://github.com/chromium/subspace/issues/333)) without leaving
    +///   requiring a native pointer to be pulled out of the `Box`.
    +/// * No native arrays, `Box` can hold [`Array`]($sus::collections::Array) or
    +///   [`std::array`](https://en.cppreference.com/w/cpp/container/array) but
    +///   avoids API complexity for supporting pointers and native arrays (which
    +///   decay to pointers) by rejecting native arrays.
    +/// * Integration with [concept type-erasure]($sus::boxed::DynConcept) for
    +///   holding and constructing from type-erased objects which satisfy a given
    +///   concept in a type-safe way and without requiring inheritence. This
    +///   construction is done through [`From`]($sus::construct::From) and thus
    +///   can `Box` can be constructed in a type-deduced way from any object
    +///   that satisfies the concept `C` via [`sus::into()`]($sus::construct::into).
    +///   This only requires that `DynC` is compatible with
    +///   [`DynConcept`]($sus::boxed::DynConcept) which is the case for all
    +///   type-erasable concepts in the Subspace library.
    +/// * Additional integration with Subspace library concepts like
    +///   [`Error`]($sus::error::Error) and [`Fn`]($sus::fn::Fn) such that `Box`
    +///   [will satisfy those concepts itself](
    +///   #box-implements-some-concepts-for-its-inner-type) when holding
    +///   a type-erased object that satisfies those concepts.
    +///
    +/// # Box implements some concepts for its inner type
    +///
    +/// The Subspace library provides a number of concepts which support
    +/// type-erasure through [`DynConcept`]($sus::boxed::DynConcept), and when
    +/// `Box` is holding these as its value, it may itself implement the concept,
    +/// forwarding use of the concept through to the inner type.
    +///
    +/// The canonical example of this is
    +/// [`Result`]($sus::result::Result)`>`, which allows construction via
    +/// `sus::err(sus::into(e))` for any `e` that satisfies
    +/// [`Error`]($sus::error::Error). The error field, now being a `Box` is still
    +/// usable as an [`Error`]($sus::error::Error) allowing generic code that
    +/// expects the [`Result`]($sus::result::Result) to hold an
    +/// [`Error`]($sus::error::Error) to function even though the actual error has
    +/// been type-erased and no longer needs the functions to be templated on it.
    +///
    +/// The following concepts, when type-erased in `Box` will also be satisfied
    +/// by the `Box` itself, avoiding the need to unwrap the inner type and allowing
    +/// the `Box` to be used in templated code requiring that concept:
    +/// * [`Error`]($sus::error::Error)
    +/// * [`Fn`]($sus::fn::Fn)
    +/// * [`FnMut`]($sus::fn::FnMut)
    +/// * [`FnOnce`]($sus::fn::FnOnce)
     template 
     class [[sus_trivial_abi]] Box final {
       static_assert(!std::is_reference_v, "Box of a reference is not allowed.");
    +  static_assert(!std::is_array_v,
    +                "Box is not allowed, use Box>");
       static_assert(sus::mem::size_of() != 0u);  // Ensure that `T` is defined.
     
      public:
    @@ -62,6 +136,22 @@ class [[sus_trivial_abi]] Box final {
         if (t_) delete t_;
       }
     
    +  /// Constructs a Box by calling the constructor of `T` with `args`.
    +  ///
    +  /// This allows construction of `T` directly on the heap, which is required
    +  /// for types which do not satisfy [`Move`]($sus::mem::Move). This is a common
    +  /// case for virtual clases which require themselves to be heap allocated.
    +  ///
    +  /// For type-erasure of concept objects using [`DynConcept`](
    +  /// $sus::boxed::DynConcept), such as [`DynError`]($sus::error::DynError),
    +  /// the [`from`]($sus::boxed::Box::from!dync) constructor method
    +  /// can be used to type erase the concept object and move it to the heap.
    +  template 
    +    requires(std::constructible_from)
    +  constexpr static Box with_args(Args&&... args) noexcept {
    +    return Box(FROM_POINTER, new T(::sus::forward(args)...));
    +  }
    +
       /// Converts `U` into a [`Box`]($sus::boxed::Box).
       ///
       /// The conversion allocates on the heap and moves `u` into it.
    @@ -69,7 +159,7 @@ class [[sus_trivial_abi]] Box final {
       /// Satisfies the [`From`]($sus::construct::From) concept for
       /// [`Box`]($sus::boxed::Box) where `U` is convertible to `T` and is not a
       /// subclass of `T`.
    -  /// #[doc.overloads=from.convert]
    +  /// #[doc.overloads=convert]
       template  U>
         requires(!::sus::ptr::SameOrSubclassOf)
       constexpr static Box from(U u) noexcept
    @@ -83,7 +173,7 @@ class [[sus_trivial_abi]] Box final {
       ///
       /// Satisfies the [`From`]($sus::construct::From) concept for
       /// [`Box`]($sus::boxed::Box) where U is `T` or a subclass of `T`.
    -  /// #[doc.overloads=from.inherit]
    +  /// #[doc.overloads=inherit]
       template 
         requires(::sus::ptr::SameOrSubclassOf)
       constexpr static Box from(U u) noexcept
    @@ -168,34 +258,42 @@ class [[sus_trivial_abi]] Box final {
         return t_;
       }
     
    -  /// Satisfies the [`From`]($sus::construct::From) concept for
    -  /// [`Box`]($sus::boxed::Box)`<`[`DynError`]($sus::error::DynError)`>` when
    -  /// `E` satisfies [`Error`]($sus::error::Error). This conversion moves and
    -  /// type-erases `E` into a heap-alloocated
    -  /// [`DynError`]($sus::error::DynError).
    +  /// For a type-erased `DynC` of a concept `C`, `Box` can be
    +  /// constructed from a type that satisfies `C`.
       ///
    -  /// #[doc.overloads=dynerror.from.error]
    -  template <::sus::error::Error E>
    -    requires(sus::mem::Move)
    -  constexpr static Box from(E e) noexcept
    -    requires(std::same_as)
    +  /// This satisfies the [`From`]($sus::construct::From) concept for
    +  /// constructing `Box` from any type that satisfies the concept `C`. It
    +  /// allows returning a non-templated type satisfying a concept.
    +  ///
    +  /// See [`DynConcept`]($sus::boxed::DynConcept) for more on type erasure of
    +  /// concept-satisfying types.
    +  ///
    +  /// #[doc.overloads=dync]
    +  template 
    +  constexpr static Box from(U u) noexcept
    +    requires(std::same_as> &&  //
    +             DynConcept &&                         //
    +             T::template SatisfiesConcept)
       {
    -    using HeapError = ::sus::error::DynErrorTyped;
    -    auto* heap_e = new HeapError(::sus::move(e));
    -    // This implicitly upcasts to the DynError.
    -    return Box(FROM_POINTER, heap_e);
    +    using DynTyped = T::template DynTyped;
    +    // This implicitly upcasts to the `DynConcept` type `T`.
    +    return Box(FROM_POINTER, new DynTyped(::sus::move(u)));
       }
     
    +  /// A `Box` can be constructed from a string, which gets type-erased
    +  /// into a type that satisfies [`Error`]($sus::error::Error).
    +
       /// Satisfies the [`From`]($sus::construct::From) concept for
       /// [`Box`]($sus::boxed::Box)`<`[`DynError`]($sus::error::DynError)`>`. This
       /// conversion moves and type-erases the `std::string` into a heap-alloocated
       /// [`DynError`]($sus::error::DynError).
       ///
    -  /// #[doc.overloads=dynerror.from.string]
    +  /// #[doc.overloads=dynerror]
       constexpr static Box from(std::string s) noexcept
         requires(std::same_as)
       {
    -    using HeapError = ::sus::error::DynErrorTyped<__private::StringError>;
    +    using HeapError = ::sus::error::DynErrorTyped<__private::StringError,
    +                                                  __private::StringError>;
         auto* heap_e = new HeapError(__private::StringError(::sus::move(s)));
         // This implicitly upcasts to the DynError.
         return Box(FROM_POINTER, heap_e);
    @@ -256,6 +354,118 @@ class [[sus_trivial_abi]] Box final {
         return ::sus::mem::replace(t_, nullptr);
       }
     
    +  /// Consumes the `Box`, calling `f` with the wrapped value before destroying
    +  /// it.
    +  ///
    +  /// This allows the caller to make use of the wrapped object as an rvalue
    +  /// without moving out of the wrapped object in a way that leaves the Box with
    +  /// a moved-from object within.
    +  template <::sus::fn::FnOnce F>
    +  constexpr ::sus::fn::ReturnOnce consume(F f) && noexcept {
    +    ::sus::check_with_message(t_, "Box used after move");
    +    ::sus::fn::ReturnOnce ret =
    +        ::sus::fn::call_once(::sus::move(f), sus::move(*t_));
    +    delete ::sus::mem::replace(t_, nullptr);
    +    return ret;
    +  }
    +
    +  /// A `Box` holding a type-erased function type will satisfy the fn concepts
    +  /// and can be used as a function type. It will forward the call through
    +  /// to the inner type.
    +  ///
    +  /// * `Box<`[`DynFn`]($sus::fn::DynFn)`>` satisfies [`Fn`]($sus::fn::Fn).
    +  /// * `Box<`[`DynFnMut`]($sus::fn::DynFnMut)`>` satisfies
    +  ///   [`FnMut`]($sus::fn::FnMut).
    +  /// * `Box<`[`DynFnOnce`]($sus::fn::DynFnOnce)`>` satisfies
    +  ///   [`FnOnce`]($sus::fn::FnOnce).
    +  ///
    +  /// The usual compatibility rules apply, allowing [`DynFn`]($sus::fn::DynFn)
    +  /// to be treated like [`DynFnMut`]($sus::fn::DynFnMut)
    +  /// and both of them to be treated like [`DynFnOnce`]($sus::fn::DynFnOnce).
    +  ///
    +  /// A `Box<`[`DynFnOnce`]($sus::fn::DynFnOnce)`>` must be moved from
    +  /// when called, and will destroy the
    +  /// underlying function object after the call completes.
    +  ///
    +  /// # Examples
    +  ///
    +  /// A `Box` being used as a function object:
    +  /// ```
    +  /// const auto b = Box>::from(
    +  ///     &std::string_view::size);
    +  /// sus::check(b("hello world") == 11u);
    +  ///
    +  /// auto mut_b = Box>::from(
    +  ///     &std::string_view::size);
    +  /// sus::check(mut_b("hello world") == 11u);
    +  ///
    +  /// sus::check(sus::move(mut_b)("hello world") == 11u);
    +  /// // The object inside `mut_b` is now destroyed.
    +  /// ```
    +  ///
    +  /// A `Box` being used as a function object. It can not be called
    +  /// on a `const Box` as it requies the ability to mutate, and `const Box`
    +  /// treats its inner object as const:
    +  /// ```
    +  /// auto mut_b = Box>::from(
    +  ///     &std::string_view::size);
    +  /// sus::check(mut_b("hello world") == 11u);
    +  ///
    +  /// sus::check(sus::move(mut_b)("hello world") == 11u);
    +  /// // The object inside `mut_b` is now destroyed.
    +  /// ```
    +  ///
    +  /// A `Box` being used as a function object. It must be an rvalue
    +  /// (either a return from a call or moved with [`move`]($sus::mem::move))
    +  /// to call through it:
    +  /// ```
    +  /// auto b = Box>::from(
    +  ///     &std::string_view::size);
    +  /// sus::check(sus::move(b)("hello world") == 11u);
    +  ///
    +  /// auto x = [] {
    +  ///   return Box>::from(
    +  ///       &std::string_view::size);
    +  /// };
    +  /// sus::check(x()("hello world") == 11u);
    +  /// ```
    +  // TODO: https://github.com/llvm/llvm-project/issues/65904
    +  // clang-format off
    +  template 
    +  constexpr sus::fn::Return operator()(Args&&... args) const&
    +    requires(T::IsDynFn &&
    +             ::sus::fn::Fn(Args...)>)
    +  {
    +    ::sus::check_with_message(t_, "Box used after move");
    +    return ::sus::fn::call(*t_, ::sus::forward(args)...);
    +  }
    +
    +  template 
    +  constexpr sus::fn::ReturnMut operator()(Args&&... args) &
    +    requires(T::IsDynFn &&
    +             ::sus::fn::FnMut(Args...)>)
    +  {
    +    ::sus::check_with_message(t_, "Box used after move");
    +    return ::sus::fn::call_mut(*t_, ::sus::forward(args)...);
    +  }
    +
    +  template 
    +  constexpr sus::fn::ReturnOnce operator()(Args&&... args) &&
    +    requires(T::IsDynFn &&  //
    +             ::sus::fn::FnOnce(Args...)>)
    +  {
    +    ::sus::check_with_message(t_, "Box used after move");
    +    struct Cleanup {
    +      constexpr ~Cleanup() noexcept { delete t; }
    +      T* t;
    +    };
    +    return ::sus::fn::call_once(
    +        sus::move(*Cleanup(::sus::mem::replace(t_, nullptr)).t),
    +                           ::sus::forward(args)...);
    +  }
    +  ;
    +  // clang-format on
    +
      private:
       enum FromPointer { FROM_POINTER };
       Box(FromPointer, T* t) : t_(t) {}
    diff --git a/sus/boxed/box_unittest.cc b/sus/boxed/box_unittest.cc
    index f51b48d71..07953d21a 100644
    --- a/sus/boxed/box_unittest.cc
    +++ b/sus/boxed/box_unittest.cc
    @@ -62,6 +62,24 @@ TEST(Box, Construct) {
       }
     }
     
    +TEST(Box, WithArgs) {
    +  struct NoMove {
    +    NoMove(i32 i) : i(i) {}
    +
    +    NoMove(NoMove&&) = delete;
    +    NoMove& operator=(NoMove&&) = delete;
    +
    +    i32 i;
    +  };
    +  static_assert(!sus::mem::Move);
    +
    +  auto b = Box::with_args(3);
    +  EXPECT_EQ(b->i, 3);
    +
    +  auto b2 = sus::move(b);
    +  EXPECT_EQ(b2->i, 3);
    +}
    +
     TEST(Box, FromT) {
       i32 i = 3;
       {
    @@ -305,6 +323,40 @@ TEST(BoxDynError, FromString) {
       }
     }
     
    +TEST(BoxDynFn, Example_Call) {
    +  {
    +    const auto b = Box>::from(
    +        &std::string_view::size);
    +    sus::check(b("hello world") == 11u);
    +
    +    auto mut_b = Box>::from(
    +        &std::string_view::size);
    +    sus::check(mut_b("hello world") == 11u);
    +
    +    sus::check(sus::move(mut_b)("hello world") == 11u);
    +    // The object inside `mut_b` is now destroyed.
    +  }
    +  {
    +    auto mut_b = Box>::from(
    +        &std::string_view::size);
    +    sus::check(mut_b("hello world") == 11u);
    +
    +    sus::check(sus::move(mut_b)("hello world") == 11u);
    +    // The object inside `mut_b` is now destroyed.
    +  }
    +  {
    +    auto b = Box>::from(
    +        &std::string_view::size);
    +    sus::check(sus::move(b)("hello world") == 11u);
    +
    +    auto x = [] {
    +      return Box>::from(
    +          &std::string_view::size);
    +    };
    +    sus::check(x()("hello world") == 11u);
    +  }
    +}
    +
     TEST(Box, fmt) {
       static_assert(fmt::is_formattable, char>::value);
       EXPECT_EQ(fmt::format("{}", Box(12345)), "12345");
    diff --git a/sus/boxed/boxed.h b/sus/boxed/boxed.h
    new file mode 100644
    index 000000000..646b0e954
    --- /dev/null
    +++ b/sus/boxed/boxed.h
    @@ -0,0 +1,25 @@
    +// Copyright 2023 Google LLC
    +//
    +// Licensed under the Apache License, Version 2.0 (the "License");
    +// you may not use this file except in compliance with the License.
    +// You may obtain a copy of the License at
    +//
    +//     https://www.apache.org/licenses/LICENSE-2.0
    +//
    +// Unless required by applicable law or agreed to in writing, software
    +// distributed under the License is distributed on an "AS IS" BASIS,
    +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +// See the License for the specific language governing permissions and
    +// limitations under the License.
    +
    +// IWYU pragma: private
    +// IWYU pragma: friend "sus/boxed/.*"
    +#pragma once
    +
    +namespace sus {
    +
    +/// The [`Box`]($sus::boxed::Box) type for heap allocation and other
    +/// tools for [type-erasure of concepts]($sus::boxed::DynConcept).
    +namespace boxed {}
    +
    +}  // namespace sus
    diff --git a/sus/boxed/dyn.h b/sus/boxed/dyn.h
    new file mode 100644
    index 000000000..f6f3dc973
    --- /dev/null
    +++ b/sus/boxed/dyn.h
    @@ -0,0 +1,461 @@
    +// Copyright 2023 Google LLC
    +//
    +// Licensed under the Apache License, Version 2.0 (the "License");
    +// you may not use this file except in compliance with the License.
    +// You may obtain a copy of the License at
    +//
    +//     https://www.apache.org/licenses/LICENSE-2.0
    +//
    +// Unless required by applicable law or agreed to in writing, software
    +// distributed under the License is distributed on an "AS IS" BASIS,
    +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +// See the License for the specific language governing permissions and
    +// limitations under the License.
    +
    +#pragma once
    +
    +#include 
    +#include 
    +
    +#include "sus/boxed/boxed.h"  // namespace docs.
    +#include "sus/macros/lifetimebound.h"
    +#include "sus/mem/forward.h"
    +#include "sus/mem/move.h"
    +
    +namespace sus::boxed {
    +
    +/// A concept for generalized type erasure of concepts, allowing use of a
    +/// concept-satisfying type `T` without knowing the concrete type `T`.
    +///
    +/// By providing a virtual type-erasure class that satisifies `DynConcept` along
    +/// with a concept `C`, it allows the use of generic concept-satisfying objects
    +/// without the use of templates.
    +/// This means a function accepting a concept-satisying object as
    +/// a parameter can:
    +/// * Be written outside of the header.
    +/// * Be a virtual method.
    +/// * Be part of a non-header-only library API.
    +///
    +/// We can not specify a concept as a type parameter so there is a level of
    +/// indirection involved and the concept itself is not named.
    +///
    +/// To type-erase a concept `C`, there must be a virtual class `DynC` declared
    +/// that satisfies this `DynConcept` concept for all concrete types `ConcreteT`
    +/// which satisfy the concept `C` being type-erased.
    +///
    +/// # Performing the type erasure
    +///
    +/// To type-erase a concept-satisfying object into the heap, use
    +/// [`Box`]($sus::boxed::Box), such as `Box` to hold a type-erased
    +/// heap-allocated object that is known to satisfy the concept `C`.
    +///
    +/// Then, `Box` will come with a method
    +/// [`from`]($sus::boxed::Box::from!dync) that lifts any object satisfying the
    +/// concept `C` into the heap and type-erases it to `DynC`. This implies that
    +/// [`Box`]($sus::boxed::Box) will satisfy the
    +/// [`From`]($sus::construct::From) concept, and can be constructed with type
    +/// deduction through [`sus::into()`]($sus::construct::into) or
    +/// explicitly with `Box::from(sus::move(satisfies_c))`.
    +///
    +/// To type-erase a concept-satisfying object into a `DynC` reference without
    +/// heap allocation, use [`dyn`]($sus::boxed::dyn), such as `dyn(x)` to
    +/// construct a type-erased reference to an object `x` that is known to satisfy
    +/// the concept `C`.
    +///
    +/// The [`dyn`]($sus::boxed::dyn) function, and its returned type should only
    +/// appear in function call arguments. The returned type
    +/// [`Dyn`]($sus::boxed::Dyn) can not be moved, and it only converts a
    +/// reference to a type `T&` into a reference `DynC&` that also satisfies `C`
    +/// but without templates.
    +/// This can be used to call functions that accept a type-erased concept
    +/// by reference, such as with a `const DynC&` parameter.
    +///
    +/// # Type erasure of concepts in the Subspace library
    +///
    +/// Some concepts in the Subspace library come with a virtual type-erasure class
    +/// that satisfies `DynConcept` and can be type-erased into `Box` for the
    +/// concept `C`:
    +/// * [`Error`]($sus::error::Error)
    +/// * [`Fn`]($sus::fn::Fn)
    +/// * [`FnMut`]($sus::fn::FnMut)
    +/// * [`FnOnce`]($sus::fn::FnOnce)
    +///
    +/// For some concepts in the Subspace library, `Box` will also satisfy the
    +/// concept `C` itself, without having use the inner type. See
    +/// [Box implements some concepts for its inner type](
    +/// $sus::boxed::Box#box-implements-some-concepts-for-its-inner-type).
    +///
    +/// Since the actual type is erased, it can not be moved or copied. While it can
    +/// be constructed on the stack or the heap, any access to it other than its
    +/// initial declaration must be through a pointer or reference, similar to
    +/// [`Pin`](https://doc.rust-lang.org/std/pin/struct.Pin.html) types in
    +/// Rust.
    +///
    +/// # Examples
    +///
    +/// ## Implementing concept type-erasure
    +///
    +/// Providing the mechanism to type erase objects that satisfy a concept named
    +/// `MyConcept` through a `DynMyConcept` class:
    +/// ```
    +/// // A concept which requires a single const-access method named `concept_fn`.
    +/// template 
    +/// concept MyConcept = requires(const T& t) {
    +///   { t.concept_fn() } -> std::same_as;
    +/// };
    +///
    +/// template 
    +/// class DynMyConceptTyped;
    +///
    +/// class DynMyConcept {
    +///   sus_dyn_concept(MyConcept, DynMyConcept, DynMyConceptTyped);
    +///
    +///  public:
    +///   // Pure virtual concept API.
    +///   virtual void concept_fn() const = 0;
    +/// };
    +/// // Verifies that DynMyConcept also satisfies MyConcept, which is required.
    +/// static_assert(MyConcept);
    +///
    +/// template 
    +/// class DynMyConceptTyped final : public DynMyConcept {
    +///   sus_dyn_concept_typed(MyConcept, DynMyConcept, DynMyConceptTyped, v);
    +///
    +///   // Virtual concept API implementation.
    +///   void concept_fn() const override { return v.concept_fn(); };
    +/// };
    +///
    +/// // A type which satiesfies `MyConcept`.
    +/// struct MyConceptType {
    +///   void concept_fn() const {}
    +/// };
    +///
    +/// int main() {
    +///   // Verifies that DynMyConcept is functioning correctly, testing it against
    +///   // a type that satisfies MyConcept.
    +///   static_assert(sus::boxed::DynConcept);
    +///
    +///   auto b = [](Box c) { c->concept_fn(); };
    +///   // `Box` constructs from `MyConceptType`.
    +///   b(sus::into(MyConceptType()));
    +///
    +///   auto d = [](const DynMyConcept& c) { c.concept_fn(); };
    +///   // `MyConceptType` converts to `const MyConcept&` with `sus::dyn()`.
    +///   d(sus::dyn(MyConceptType()));
    +/// }
    +/// ```
    +///
    +/// An identical example to above, with a `DynMyConcept` class providing type
    +/// erasure for the `MyConcept` concept, however without the use of the helper
    +/// macros, showing all the required machinery:
    +/// ```
    +/// // A concept which requires a single const-access method named `concept_fn`.
    +/// template 
    +/// concept MyConcept = requires(const T& t) {
    +///   { t.concept_fn() } -> std::same_as;
    +/// };
    +///
    +/// template 
    +/// class DynMyConceptTyped;
    +///
    +/// class DynMyConcept {
    +///  public:
    +///   // Pure virtual concept API.
    +///   virtual void concept_fn() const = 0;
    +///   template 
    +///
    +///   static constexpr bool SatisfiesConcept = MyConcept;
    +///   template 
    +///   using DynTyped = DynMyConceptTyped;
    +///
    +///   DynMyConcept() = default;
    +///   virtual ~DynMyConcept() = default;
    +///   DynMyConcept(DynC&&) = delete;
    +///   DynMyConcept& operator=(DynMyConcept&&) = delete;
    +/// };
    +/// // Verifies that DynMyConcept also satisfies MyConcept, which is required.
    +/// static_assert(MyConcept);
    +///
    +/// template 
    +/// class DynMyConceptTyped final : public DynMyConcept {
    +///  public:
    +///   // Virtual concept API implementation.
    +///   void concept_fn() const override { return c_.concept_fn(); };
    +///
    +///   constexpr DynMyConceptTyped(Store&& c) : c_(::sus::forward(c)) {}
    +///
    +///  private:
    +///   Store c_;
    +/// };
    +///
    +/// // A type which satiesfies `MyConcept`.
    +/// struct MyConceptType {
    +///   void concept_fn() const {}
    +/// };
    +///
    +/// int main() {
    +///   // Verifies that DynMyConcept is functioning correctly, testing it against
    +///   // a type that satisfies MyConcept.
    +///   static_assert(sus::boxed::DynConcept);
    +///
    +///   auto b = [](Box c) { c->concept_fn(); };
    +///   // `Box` constructs from `MyConceptType`.
    +///   b(sus::into(MyConceptType()));
    +///
    +///   auto d = [](const DynMyConcept& c) { c.concept_fn(); };
    +///   // `MyConceptType` converts to `const MyConcept&` with `sus::dyn()`.
    +///   d(sus::dyn(MyConceptType()));
    +/// }
    +/// ```
    +///
    +/// ## Holding dyn() in a stack variable
    +///
    +/// When a function receives a type-erased `DynC&` by reference, it allows the
    +/// caller to avoid heap allocations should they wish. In the easy case, the
    +/// caller will simply call `sus::dyn()` directly in the function arguments to
    +/// construct the `DynC&` reference, which ensures it outlives the function
    +/// call.
    +///
    +/// In a more complicated scenario, the caller may wish to conditionally decide
    +/// to pass an Option with or without a reference, or to choose between
    +/// different references. It is not possible to return the result of
    +/// `sus::dyn()` without creating a dangling stack reference, which will be
    +/// caught by clang in most cases. This means in particular that lambdas such
    +/// as those passed to functions like [`Option::map`]($sus::option::Option::map)
    +/// can not be used to construct the `DynC&` reference.
    +///
    +/// In order to ensure the target of the `DynC&` reference outlives the function
    +/// it can be constructed as a stack variable before calling the function.
    +/// ```
    +/// std::srand(sus::mog(std::time(nullptr)));
    +///
    +/// auto x = [](sus::Option&> fn) {
    +///   if (fn.is_some())
    +///     return sus::move(fn).unwrap()();
    +///   else
    +///     return std::string("tails");
    +/// };
    +///
    +/// auto heads = [] { return std::string("heads"); };
    +/// // Type-erased `Fn` that represents `heads`. Placed on the
    +/// // stack to outlive its use in the `Option` and the call to `x(cb)`.
    +/// auto dyn_heads = sus::dyn>(heads);
    +/// // Conditionally holds a type-erased reference to `heads`. This requires a
    +/// // type-erasure that outlives the `cb` variable.
    +/// auto cb = [&]() -> sus::Option&> {
    +///   if (std::rand() % 2) return sus::some(dyn_heads);
    +///   return sus::none();
    +/// }();
    +///
    +/// std::string s = x(cb);
    +///
    +/// fmt::println("{}", s);  // Prints one of "heads" or "tails.
    +/// ```
    +/// It can greatly simplify correctness of code to use owned type-erased
    +/// concept objects through [`Box`]($sus::boxed::Box), such as
    +/// `Box>` in the above example. Though references can be
    +/// useful, especially in simple or perf-critical code paths.
    +template 
    +concept DynConcept = requires {
    +  // The types are not qualified or references.
    +  requires std::same_as>;
    +  requires std::same_as>;
    +
    +  // The SatisfiesConcept bool tests against the concept.
    +  { DynC::template SatisfiesConcept } -> std::same_as;
    +  // The `DynTyped` type alias names the typed subclass. The `DynTyped` class
    +  // has two template parameters, the concrete type and the storage type (value
    +  // or reference).
    +  typename DynC::template DynTyped;
    +
    +  // The type-erased `DynC` must also satisfy the concept, so it can be used
    +  // in templated code still as well.
    +  requires DynC::template SatisfiesConcept;
    +
    +  // The typed class is a subclass of the type-erased `DynC` base class, and is
    +  // final.
    +  requires std::is_base_of_v<
    +      DynC, typename DynC::template DynTyped>;
    +  requires std::is_final_v<
    +      typename DynC::template DynTyped>;
    +
    +  // The type-erased `DynC` can not be moved (which would slice the typed
    +  // subclass off).
    +  requires !std::is_move_constructible_v;
    +  requires !std::is_move_assignable_v;
    +};
    +
    +/// A type erasure of a type satisfying a concept, which can be used as a
    +/// reference without heap allocation or templates.
    +/// Returned from [`dyn`]($sus::boxed::dyn).
    +///
    +/// This type is similar to `Box` for purposes of type erasure but does
    +/// not require heap allocation,
    +/// and it converts directly to a reference to the erased type.
    +///
    +/// Use [`dyn`]($sus::boxed::dyn) to convert to a `DynC` reference instead of
    +/// constructing this type directly.
    +///
    +/// See [`DynConcept`]($sus::boxed::DynConcept) for more on type erasure of
    +/// concept-satisfying types.
    +template 
    +class [[nodiscard]] Dyn {
    + public:
    +  static_assert(std::same_as>,
    +                "DynC can be const-qualified but not a reference");
    +  static_assert(std::same_as>,
    +                "ConcreteT can not be qualified or a reference");
    +
    +  static_assert(
    +      DynC::template SatisfiesConcept,
    +      "ConcreteT must satisfy the concept that DynC type-erases for.");
    +
    +  /// Construct a `Dyn` from a mutable reference to `T`, which will
    +  /// vend a mutable reference `DynC&`.
    +  ///
    +  /// #[doc.overloads=mut]
    +  Dyn(ConcreteT& concrete sus_lifetimebound)
    +    requires(!std::is_const_v)
    +      : dyn_(concrete) {}
    +  /// #[doc.overloads=mut]
    +  Dyn(ConcreteT&& concrete sus_lifetimebound)
    +    requires(!std::is_const_v)
    +      : dyn_(concrete) {}
    +  /// Construct a `Dyn` from a reference to `T`, which will
    +  /// vend a const reference `const DynC&`.
    +  ///
    +  /// #[doc.overloads=const]
    +  Dyn(const ConcreteT& concrete sus_lifetimebound)
    +    requires(std::is_const_v)
    +      // This drops the const qualifier on `concrete` however we have a const
    +      // qualifier on `DynC` (checked by the requires clause on this
    +      // constructor) which prevents the `concrete` from being accessed in a
    +      // non-const way through the `operator DynC&` overloads.
    +      : dyn_(const_cast(concrete)) {}
    +
    +  /// Converts the reference to `ConcreteT` into a `DynC` reference.
    +  operator const DynC&() const& { return dyn_; }
    +  operator DynC&() &
    +    requires(!std::is_const_v)
    +  {
    +    return dyn_;
    +  }
    +  operator DynC&() &&
    +    requires(!std::is_const_v)
    +  {
    +    return dyn_;
    +  }
    +  operator DynC&&() &&
    +    requires(!std::is_const_v)
    +  {
    +    return ::sus::move(dyn_);
    +  }
    +
    +  /// `Dyn` can not be moved.
    +  ///
    +  /// `Dyn` only exists as a temporary to convert a
    +  /// concrete reference to a concept type to into a type-erased reference.
    +  Dyn(Dyn&&) = delete;
    +  /// `Dyn` can not be moved.
    +  ///
    +  /// `Dyn` only exists as a temporary to convert a
    +  /// concrete reference to a concept type to into a type-erased reference.
    +  Dyn& operator=(Dyn&&) = delete;
    +
    + private:
    +  /// The typed subclass of `DynC` which holds the reference to `ConcreteT`.
    +  typename DynC::template DynTyped dyn_;
    +};
    +
    +/// Type erases a reference to a type `T&` which satisfies a concept `C`,
    +/// into a reference `DynC&` that also satisfies `C` but without templates.
    +///
    +/// Use `dyn(x)` to convert a mutable reference to `x` into `DynC&` and
    +/// `dyn(x)` to convert a const or mutable reference to `x` into
    +/// `const Dyn&`.
    +///
    +/// Type erasure into `DynC` allows calling a method that receives a `DynC`
    +/// reference, such as `const DynC&`, without requiring a heap allocation into
    +/// a `Box`.
    +///
    +/// See [`DynConcept`]($sus::boxed::DynConcept) for more on type erasure of
    +/// concept-satisfying types.
    +template 
    +  requires(std::same_as> &&  //
    +           std::same_as>)
    +constexpr Dyn dyn(ConcreteT& t sus_lifetimebound) noexcept {
    +  return Dyn(t);
    +}
    +template 
    +  requires(std::same_as> &&            //
    +           std::same_as> &&  //
    +           std::is_rvalue_reference_v)
    +constexpr Dyn dyn(ConcreteT&& t sus_lifetimebound) noexcept {
    +  return Dyn(t);
    +}
    +template 
    +  requires(std::same_as> &&
    +           std::same_as> &&
    +           std::is_const_v)
    +constexpr Dyn dyn(
    +    const ConcreteT& t sus_lifetimebound) noexcept {
    +  return Dyn(t);
    +}
    +
    +}  // namespace sus::boxed
    +
    +// Promote `dyn` to the top `sus` namespace.
    +namespace sus {
    +using sus::boxed::dyn;
    +}
    +
    +/// Macro to help implement `DynC` for a concept `C`. The macro is placed in the
    +/// body of the `DynC` class.
    +///
    +/// Here `DynC` is used as a placeholder name to refer to the virtual class
    +/// that type-erases for the concept `C`. The type erasure class is typically
    +/// named to match the concept, with a "Dyn" prefix. The type-aware subclass
    +/// of the type erasure class is typically named to match the concept with a
    +/// "Dyn" prefix and a "Typed" suffix.
    +///
    +/// The `Concept` parameter is the concept `C` for which types are being
    +/// type-erased.
    +///
    +/// The `DynConcept` parameter is the name of the type-erasure
    +/// class `DynC` which the macro is written within, and which has a pure virtual
    +/// interface matching the concept's requirements.
    +///
    +/// The `DynConceptTyped`
    +/// parameter is the type-aware subclass of `DynC` which contains the
    +/// `sus_dyn_concept_typed` macro in its body, and the
    +/// implementation of the virtual interface that forwards calls through to the
    +/// concrete type.
    +///
    +/// See [`DynConcept`]($sus::boxed::DynConcept) for more on type erasure of
    +/// concept-satisfying types, and [DynConcept examples](
    +/// $sus::boxed::DynConcept#examples) for examples of using the macro.
    +#define sus_dyn_concept(Concept, DynConcept, DynConceptTyped)  \
    + public:                                                       \
    +  template                                    \
    +  static constexpr bool SatisfiesConcept = Concept; \
    +  template                       \
    +  using DynTyped = DynConceptTyped;          \
    +                                                               \
    +  DynConcept() = default;                                      \
    +  virtual ~DynConcept() = default;                             \
    +  DynConcept(DynConcept&&) = delete;                           \
    +  DynConcept& operator=(DynConcept&&) = delete
    +
    +/// Macro to help implement `DynCTyped` for a concept `C`. The macro is placed
    +/// in the body of the `DynCTyped` class.
    +///
    +/// See the TODO: link [`sus_dyn_concept`] macro for more, and
    +/// [DynConcept examples]($sus::boxed::DynConcept#examples) for examples
    +/// of using the macro.
    +#define sus_dyn_concept_typed(Concept, DynConcept, DynConceptTyped, VarName)  \
    + public:                                                                      \
    +  static_assert(Concept);                                                  \
    +  constexpr DynConceptTyped(Store&& c) : VarName(::sus::forward(c)) {} \
    +                                                                              \
    + private:                                                                     \
    +  Store VarName;
    diff --git a/sus/boxed/dyn_unittest.cc b/sus/boxed/dyn_unittest.cc
    new file mode 100644
    index 000000000..b3b6773eb
    --- /dev/null
    +++ b/sus/boxed/dyn_unittest.cc
    @@ -0,0 +1,367 @@
    +// Copyright 2023 Google LLC
    +//
    +// Licensed under the Apache License, Version 2.0 (the "License");
    +// you may not use this file except in compliance with the License.
    +// You may obtain a copy of the License at
    +//
    +//     https://www.apache.org/licenses/LICENSE-2.0
    +//
    +// Unless required by applicable law or agreed to in writing, software
    +// distributed under the License is distributed on an "AS IS" BASIS,
    +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +// See the License for the specific language governing permissions and
    +// limitations under the License.
    +
    +#include "sus/boxed/dyn.h"
    +
    +#include "googletest/include/gtest/gtest.h"
    +#include "sus/boxed/box.h"
    +#include "sus/prelude.h"
    +
    +namespace {
    +using namespace sus::boxed;
    +
    +/// Some concept which requires two functions.
    +template 
    +concept C = requires(const T& c, T& m) {
    +  { c.concept_fn() } -> std::same_as;
    +  { m.concept_fn_mut() } -> std::same_as;
    +};
    +
    +template 
    +struct DynCTyped;
    +
    +/// The C concept when type-erased.
    +struct DynC {
    +  template 
    +  static constexpr bool SatisfiesConcept = C;
    +  template 
    +  using DynTyped = DynCTyped;
    +
    +  DynC() = default;
    +  virtual ~DynC() = default;
    +  DynC(DynC&&) = delete;
    +  DynC& operator=(DynC&&) = delete;
    +
    +  // Virtual concept API.
    +  virtual i32 concept_fn() const = 0;
    +  virtual i32 concept_fn_mut() = 0;
    +};
    +
    +/// DynC satisfies concept C.
    +static_assert(C);
    +
    +/// The implementation of type-erasure for the C concept.
    +template 
    +struct DynCTyped final : public DynC {
    +  constexpr DynCTyped(Store&& c) : c_(sus::forward(c)) {}
    +
    +  constexpr i32 concept_fn() const override { return c_.concept_fn(); }
    +  constexpr i32 concept_fn_mut() override { return c_.concept_fn_mut(); }
    +
    + private:
    +  Store c_;
    +};
    +
    +/// Foo satisfies concept C.
    +struct Foo final {
    +  i32 concept_fn() const noexcept { return called_const += 1, called_const; }
    +  i32 concept_fn_mut() noexcept { return called_mut += 1, called_mut; }
    +
    +  mutable i32 called_const;
    +  i32 called_mut;
    +};
    +static_assert(C);
    +
    +/// These act on the `C` concept but without being templated.
    +i32 GiveC(const DynC& c) { return c.concept_fn(); }
    +i32 GiveCMut(DynC& c) { return c.concept_fn_mut(); }
    +i32 GiveCRval(DynC&& c) { return c.concept_fn_mut(); }
    +Box GiveBoxC(Box c) { return c; }
    +
    +/// `DynC` satisfies `DynConcept` with an implementation of `C` (which is `Foo`
    +/// here).
    +static_assert(sus::boxed::DynConcept);
    +
    +TEST(Dyn, Box) {
    +  // Box::from(C) exists since DynC exists and satisfies `DynConcept` for `C`.
    +  {
    +    static_assert(sus::construct::From, Foo>);
    +    auto b = Box::from(Foo());
    +    EXPECT_EQ(b->concept_fn(), 1);
    +    EXPECT_EQ(b->concept_fn(), 2);
    +    EXPECT_EQ(b->concept_fn_mut(), 1);
    +    const auto bc = sus::move(b);
    +    EXPECT_EQ(bc->concept_fn(), 3);
    +  }
    +  // Into works.
    +  {
    +    static_assert(sus::construct::Into>);
    +    auto b = GiveBoxC(sus::into(Foo()));
    +    EXPECT_EQ(b->concept_fn(), 1);
    +    EXPECT_EQ(b->concept_fn(), 2);
    +    EXPECT_EQ(b->concept_fn_mut(), 1);
    +  }
    +}
    +
    +template 
    +concept CanGiveCFromStruct = requires(Ref r) {
    +  { GiveC(Dyn(r)) };
    +};
    +template 
    +concept CanGiveCMutFromStruct = requires(Ref r) {
    +  { GiveCMut(Dyn(r)) };
    +};
    +template 
    +concept CanGiveCRvalFromStruct = requires(Ref r) {
    +  { GiveCMut(Dyn(r)) };
    +};
    +
    +// Tests the semantics of the struct itself, though it's not used directly.
    +TEST(Dyn, DynStruct) {
    +  // Mutable.
    +  {
    +    Foo f;
    +
    +    static_assert(CanGiveCFromStruct);
    +    static_assert(CanGiveCMutFromStruct);
    +    static_assert(CanGiveCRvalFromStruct);
    +    static_assert(CanGiveCFromStruct);
    +    // Can't give a const `DynC` to a mutable reference `DynC&`.
    +    static_assert(!CanGiveCMutFromStruct);
    +    // Can't give a const `DynC` to an rvalue reference `DynC&&`
    +    static_assert(!CanGiveCRvalFromStruct);
    +
    +    EXPECT_EQ(GiveC(Dyn(f)), 1);
    +    EXPECT_EQ(GiveC(Dyn(f)), 2);
    +    EXPECT_EQ(GiveCMut(Dyn(f)), 1);
    +    EXPECT_EQ(GiveC(Dyn(f)), 3);
    +    EXPECT_EQ(GiveC(Dyn(f)), 4);
    +    // ERROR: Can't give a const `DynC` to a mutable reference `DynC&`.
    +    // GiveCMut(Dyn(f));
    +
    +    EXPECT_EQ(GiveCRval(Dyn(Foo())), 1);
    +  }
    +  // Const.
    +  {
    +    const Foo f;
    +
    +    // Can't use a const `Foo` to construct a mutable `DynC`.
    +    static_assert(!CanGiveCFromStruct);
    +    // Can't use a const `Foo` to construct a mutable `DynC&`.
    +    static_assert(!CanGiveCMutFromStruct);
    +    // Can't use a const `Foo` to construct an rvalue reference`DynC&&`.
    +    static_assert(!CanGiveCRvalFromStruct);
    +    static_assert(CanGiveCFromStruct);
    +    // Can't give a const `DynC` to a mutable reference `DynC&`.
    +    static_assert(!CanGiveCMutFromStruct);
    +    // Can't give a const `DynC` to an rvalue reference `DynC&&`
    +    static_assert(!CanGiveCRvalFromStruct);
    +
    +    EXPECT_EQ(GiveC(Dyn(f)), 1);
    +    EXPECT_EQ(GiveC(Dyn(f)), 2);
    +    // ERROR: Can't use a const `Foo` to construct a mutable `DynC`.
    +    // GiveC(Dyn(f));
    +    // GiveCMut(Dyn(f));
    +    // ERROR: Can't give a const `DynC` to a mutable reference `DynC&`.
    +    // GiveCMut(Dyn(f));
    +  }
    +
    +  // ERROR: Holding a reference to a temporary (on clang only).
    +  // TODO: How to test this with a concept?
    +  // [[maybe_unused]] auto x = Dyn(Foo());
    +}
    +
    +template 
    +concept CanGiveCMut = requires(Ref r) {
    +  { GiveCMut(sus::dyn(r)) };
    +};
    +template 
    +concept CanGiveC = requires(Ref r) {
    +  { GiveC(sus::dyn(r)) };
    +};
    +
    +TEST(Dyn, DynFunction) {
    +  // Mutable.
    +  {
    +    Foo f;
    +
    +    static_assert(CanGiveC);
    +    static_assert(CanGiveCMut);
    +    static_assert(CanGiveC);
    +    // Can't give a const `DynC` to a mutable reference `DynC&`.
    +    static_assert(!CanGiveCMut);
    +
    +    EXPECT_EQ(GiveC(sus::dyn(f)), 1);
    +    EXPECT_EQ(GiveC(sus::dyn(f)), 2);
    +    EXPECT_EQ(GiveCMut(sus::dyn(f)), 1);
    +    EXPECT_EQ(GiveC(sus::dyn(f)), 3);
    +    EXPECT_EQ(GiveC(sus::dyn(f)), 4);
    +    // ERROR: Can't give a const `DynC` to a mutable reference `DynC&`.
    +    // GiveCMut(sus::dyn(f));
    +  }
    +  // Const.
    +  {
    +    const Foo f;
    +
    +    // Can't use a const `Foo` to construct a mutable `DynC`.
    +    static_assert(!CanGiveC);
    +    // Can't use a const `Foo` to construct a mutable `DynC&`.
    +    static_assert(!CanGiveCMut);
    +    static_assert(CanGiveC);
    +    // Can't give a const `DynC` to a mutable reference `DynC&`.
    +    static_assert(!CanGiveCMut);
    +
    +    EXPECT_EQ(GiveC(sus::dyn(f)), 1);
    +    EXPECT_EQ(GiveC(sus::dyn(f)), 2);
    +    // ERROR: Can't use a const `Foo` to construct a mutable `DynC`.
    +    // GiveC(sus::dyn(f));
    +    // GiveCMut(sus::dyn(f));
    +    // ERROR: Can't give a const `DynC` to a mutable reference `DynC&`.
    +    // GiveCMut(sus::dyn(f));
    +  }
    +
    +  // ERROR: Holding a reference to a temporary (on clang only).
    +  // TODO: How to test this with a concept?
    +  // [[maybe_unused]] auto x = sus::dyn(Foo());
    +}
    +
    +namespace example_no_macro {
    +
    +// A concept which requires a single const-access method named `concept_fn`.
    +template 
    +concept MyConcept = requires(const T& t) {
    +  { t.concept_fn() } -> std::same_as;
    +};
    +
    +template 
    +class DynMyConceptTyped;
    +
    +class DynMyConcept {
    + public:
    +  // Pure virtual concept API.
    +  virtual void concept_fn() const = 0;
    +  template 
    +
    +  static constexpr bool SatisfiesConcept = MyConcept;
    +  template 
    +  using DynTyped = DynMyConceptTyped;
    +
    +  DynMyConcept() = default;
    +  virtual ~DynMyConcept() = default;
    +  DynMyConcept(DynC&&) = delete;
    +  DynMyConcept& operator=(DynMyConcept&&) = delete;
    +};
    +// Verifies that DynMyConcept also satisfies MyConcept, which is required.
    +static_assert(MyConcept);
    +
    +template 
    +class DynMyConceptTyped final : public DynMyConcept {
    + public:
    +  // Virtual concept API implementation.
    +  void concept_fn() const override { return c_.concept_fn(); };
    +
    +  constexpr DynMyConceptTyped(Store&& c) : c_(sus::forward(c)) {}
    +
    + private:
    +  Store c_;
    +};
    +
    +// A type which satiesfies `MyConcept`.
    +struct MyConceptType {
    +  void concept_fn() const {}
    +};
    +
    +TEST(Dyn, Example_NoMacro) {
    +  // Verifies that DynMyConcept is functioning correctly, testing it against
    +  // a type that satisfies MyConcept.
    +  static_assert(sus::boxed::DynConcept);
    +
    +  auto b = [](Box c) { c->concept_fn(); };
    +  // `Box` constructs from `MyConceptType`.
    +  b(sus::into(MyConceptType()));
    +
    +  auto d = [](const DynMyConcept& c) { c.concept_fn(); };
    +  // `MyConceptType` converts to `const MyConcept&` with `sus::dyn()`.
    +  d(sus::dyn(MyConceptType()));
    +}
    +
    +}  // namespace example_no_macro
    +
    +namespace example_macro {
    +
    +// A concept which requires a single const-access method named `concept_fn`.
    +template 
    +concept MyConcept = requires(const T& t) {
    +  { t.concept_fn() } -> std::same_as;
    +};
    +
    +template 
    +class DynMyConceptTyped;
    +
    +class DynMyConcept {
    +  sus_dyn_concept(MyConcept, DynMyConcept, DynMyConceptTyped);
    +
    + public:
    +  // Pure virtual concept API.
    +  virtual void concept_fn() const = 0;
    +};
    +// Verifies that DynMyConcept also satisfies MyConcept, which is required.
    +static_assert(MyConcept);
    +
    +template 
    +class DynMyConceptTyped final : public DynMyConcept {
    +  sus_dyn_concept_typed(MyConcept, DynMyConcept, DynMyConceptTyped, v);
    +
    +  // Virtual concept API implementation.
    +  void concept_fn() const override { return v.concept_fn(); };
    +};
    +
    +// A type which satiesfies `MyConcept`.
    +struct MyConceptType {
    +  void concept_fn() const {}
    +};
    +
    +TEST(Dyn, Example_Macro) {
    +  // Verifies that DynMyConcept is functioning correctly, testing it against
    +  // a type that satisfies MyConcept.
    +  static_assert(sus::boxed::DynConcept);
    +
    +  auto b = [](Box c) { c->concept_fn(); };
    +  // `Box` constructs from `MyConceptType`.
    +  b(sus::into(MyConceptType()));
    +
    +  auto d = [](const DynMyConcept& c) { c.concept_fn(); };
    +  // `MyConceptType` converts to `const MyConcept&` with `sus::dyn()`.
    +  d(sus::dyn(MyConceptType()));
    +}
    +
    +}  // namespace example_macro
    +
    +TEST(Dyn, Example_Stack) {
    +  std::srand(sus::mog(std::time(nullptr)));
    +
    +  auto x = [](sus::Option&> fn) {
    +    if (fn.is_some())
    +      return sus::move(fn).unwrap()();
    +    else
    +      return std::string("tails");
    +  };
    +
    +  auto heads = [] { return std::string("heads"); };
    +  // Type-erased `Fn` that represents `heads`. Placed on the
    +  // stack to outlive its use in the `Option` and the call to `x(cb)`.
    +  auto dyn_heads = sus::dyn>(heads);
    +  // Conditionally holds a type-erased reference to `heads`. This requires a
    +  // type-erasure that outlives the `cb` variable.
    +  auto cb = [&]() -> sus::Option&> {
    +    if (std::rand() % 2) return sus::some(dyn_heads);
    +    return sus::none();
    +  }();
    +
    +  std::string s = x(cb);
    +
    +  fmt::println("{}", s);  // Prints one of "heads" or "tails.
    +}
    +
    +}  // namespace
    diff --git a/sus/choice/choice_unittest.cc b/sus/choice/choice_unittest.cc
    index d796bc38f..bfb47156e 100644
    --- a/sus/choice/choice_unittest.cc
    +++ b/sus/choice/choice_unittest.cc
    @@ -619,12 +619,12 @@ TEST(Choice, Clone) {
     }
     
     template 
    -concept CanGetRef = requires(T t) { t.template as(); };
    +concept CanGetRef = requires(T& t) { t.template as(); };
     template 
    -concept CanGetMut = requires(T t) { t.template as_mut(); };
    +concept CanGetMut = requires(T& t) { t.template as_mut(); };
     template 
     concept CanIntoInner =
    -    requires(T t) { sus::move(t).template into_inner(); };
    +    requires(T& t) { sus::move(t).template into_inner(); };
     
     TEST(Choice, Eq) {
       struct NotEq {};
    diff --git a/sus/collections/__private/slice_methods.inc b/sus/collections/__private/slice_methods.inc
    index 8cba107ed..294428931 100644
    --- a/sus/collections/__private/slice_methods.inc
    +++ b/sus/collections/__private/slice_methods.inc
    @@ -112,7 +112,7 @@ binary_search(const T& x) const& noexcept
     /// element could be inserted while maintaining sorted order.
     constexpr ::sus::result::Result<::sus::num::usize, ::sus::num::usize>
     binary_search_by(
    -    ::sus::fn::FnMutRef f) const& noexcept {
    +    ::sus::fn::FnMut auto f) const& noexcept {
       using Result = ::sus::result::Result<::sus::num::usize, ::sus::num::usize>;
     
       // INVARIANTS:
    @@ -518,7 +518,7 @@ constexpr ::sus::Option last() && = delete;
     /// See also `binary_search()`, `binary_search_by()`, and
     /// `binary_search_by_key()`.
     constexpr ::sus::num::usize partition_point(
    -    ::sus::fn::FnMutRef pred) const& noexcept {
    +    ::sus::fn::FnMut auto pred) const& noexcept {
       return binary_search_by([pred = ::sus::move(pred)](const T& x) {
                if (::sus::fn::call_mut(pred, x)) {
                  return std::strong_ordering::less;
    @@ -642,13 +642,15 @@ constexpr ::sus::collections::Vec repeat(usize n) const& noexcept
     ///
     /// As with `split()`, if the first or last element is matched, an empty slice
     /// will be the first (or last) item returned by the iterator.
    -constexpr RSplit rsplit(
    -    ::sus::fn::FnMutRef pred) const& noexcept {
    -  return RSplit(Split(_iter_refs_expr, *this, ::sus::move(pred)));
    +template <::sus::fn::FnMut Pred>
    +constexpr RSplit rsplit(Pred pred) const& noexcept {
    +  return RSplit(
    +      Split(_iter_refs_expr, *this, ::sus::move(pred)));
     }
     
     #if _delete_rvalue
    -constexpr Split rsplit(::sus::fn::FnMutRef) && = delete;
    +template <::sus::fn::FnMut Pred>
    +constexpr Split rsplit(Pred) && = delete;
     #endif
     
     /// Returns an iterator over subslices separated by elements that match `pred`
    @@ -656,15 +658,17 @@ constexpr Split rsplit(::sus::fn::FnMutRef) && = delete;
     /// and works backwards. The matched element is not contained in the subslices.
     ///
     /// The last element returned, if any, will contain the remainder of the slice.
    -constexpr RSplitN rsplitn(
    -    usize n, ::sus::fn::FnMutRef pred) const& noexcept {
    -  return RSplitN(
    -      RSplit(Split(_iter_refs_expr, *this, ::sus::move(pred))), n);
    +template <::sus::fn::FnMut Pred>
    +constexpr RSplitN rsplitn(usize n, Pred pred) const& noexcept {
    +  return RSplitN(  //
    +      RSplit(
    +          Split(_iter_refs_expr, *this, ::sus::move(pred))),
    +      n);
     }
     
     #if _delete_rvalue
    -constexpr RSplit rsplitn(
    -    usize n, ::sus::fn::FnMutRef pred) && = delete;
    +template <::sus::fn::FnMut Pred>
    +constexpr RSplit rsplitn(usize n, Pred pred) && = delete;
     #endif
     
     /// Returns an iterator over subslices separated by elements that match `pred`.
    @@ -673,13 +677,14 @@ constexpr RSplit rsplitn(
     /// If the first element is matched, an empty slice will be the first item
     /// returned by the iterator. Similarly, if the last element in the slice is
     /// matched, an empty slice will be the last item returned by the iterator.
    -constexpr Split split(
    -    ::sus::fn::FnMutRef pred) const& noexcept {
    -  return Split(_iter_refs_expr, *this, ::sus::move(pred));
    +template <::sus::fn::FnMut Pred>
    +constexpr Split split(Pred pred) const& noexcept {
    +  return Split(_iter_refs_expr, *this, ::sus::move(pred));
     }
     
     #if _delete_rvalue
    -constexpr Split split(::sus::fn::FnMutRef) && = delete;
    +template <::sus::fn::FnMut Pred>
    +constexpr Split split(Pred) && = delete;
     #endif
     
     /// Divides one slice into two at an index.
    @@ -756,14 +761,14 @@ constexpr ::sus::Option<::sus::Tuple>> split_first() && =
     /// If the last element of the slice is matched, that element will be considered
     /// the terminator of the preceding slice. That slice will be the last item
     /// returned by the iterator.
    -constexpr SplitInclusive split_inclusive(
    -    ::sus::fn::FnMutRef pred) const& noexcept {
    -  return SplitInclusive(_iter_refs_expr, *this, ::sus::move(pred));
    +template <::sus::fn::FnMut Pred>
    +constexpr SplitInclusive split_inclusive(Pred pred) const& noexcept {
    +  return SplitInclusive(_iter_refs_expr, *this, ::sus::move(pred));
     }
     
     #if _delete_rvalue
    -constexpr SplitInclusive split_inclusive(
    -    ::sus::fn::FnMutRef) && = delete;
    +template <::sus::fn::FnMut Pred>
    +constexpr SplitInclusive split_inclusive(Pred) && = delete;
     #endif
     
     /// Returns the last and all the rest of the elements of the slice, or `None` if
    @@ -786,14 +791,15 @@ constexpr ::sus::Option<::sus::Tuple>> split_last() && =
     /// in the subslices.
     ///
     /// The last element returned, if any, will contain the remainder of the slice.
    -constexpr SplitN splitn(
    -    usize n, ::sus::fn::FnMutRef pred) const& noexcept {
    -  return SplitN(Split(_iter_refs_expr, *this, ::sus::move(pred)), n);
    +template <::sus::fn::FnMut Pred>
    +constexpr SplitN splitn(usize n, Pred pred) const& noexcept {
    +  return SplitN(
    +      Split(_iter_refs_expr, *this, ::sus::move(pred)), n);
     }
     
     #if _delete_rvalue
    -constexpr Split splitn(usize n,
    -                          ::sus::fn::FnMutRef pred) && = delete;
    +template <::sus::fn::FnMut Pred>
    +constexpr Split splitn(usize n, Pred pred) && = delete;
     #endif
     
     /// Returns `true` if `needle` is a prefix of the slice.
    diff --git a/sus/collections/__private/slice_mut_methods.inc b/sus/collections/__private/slice_mut_methods.inc
    index f74097fd2..af60d4b88 100644
    --- a/sus/collections/__private/slice_mut_methods.inc
    +++ b/sus/collections/__private/slice_mut_methods.inc
    @@ -233,7 +233,7 @@ constexpr void fill(T value) NO_RETURN_REF noexcept
     /// This method uses a closure to create new values. If you’d rather `Clone` a
     /// given value, use `fill()`. If you want to default-construct elements for a
     /// type that satisfies `sus::construct::Default`, use `fill_with_default()`.
    -constexpr void fill_with(::sus::fn::FnMutRef f) NO_RETURN_REF noexcept {
    +constexpr void fill_with(::sus::fn::FnMut auto f) NO_RETURN_REF noexcept {
       T* ptr = as_mut_ptr();
       T* const end_ptr = ptr + len();
       while (ptr != end_ptr) {
    @@ -527,9 +527,10 @@ void rotate_right(::sus::num::usize k) NO_RETURN_REF noexcept
     ///
     /// As with `split_mut()`, if the first or last element is matched, an empty
     /// slice will be the first (or last) item returned by the iterator.
    -constexpr RSplitMut rsplit_mut(::sus::fn::FnMutRef pred)
    -    RETURN_REF noexcept {
    -  return RSplitMut(SplitMut(_iter_refs_expr, *this, ::sus::move(pred)));
    +template <::sus::fn::FnMut Pred>
    +constexpr RSplitMut rsplit_mut(Pred pred) RETURN_REF noexcept {
    +  return RSplitMut(
    +      SplitMut(_iter_refs_expr, *this, ::sus::move(pred)));
     }
     
     /// Returns an iterator over subslices separated by elements that match `pred`
    @@ -537,10 +538,13 @@ constexpr RSplitMut rsplit_mut(::sus::fn::FnMutRef pred)
     /// and works backwards. The matched element is not contained in the subslices.
     ///
     /// The last element returned, if any, will contain the remainder of the slice.
    -constexpr RSplitNMut rsplitn_mut(
    -    usize n, ::sus::fn::FnMutRef pred) RETURN_REF noexcept {
    -  return RSplitNMut(
    -      RSplitMut(SplitMut(_iter_refs_expr, *this, ::sus::move(pred))), n);
    +template <::sus::fn::FnMut Pred>
    +constexpr RSplitNMut rsplitn_mut(usize n,
    +                                          Pred pred) RETURN_REF noexcept {
    +  return RSplitNMut(  //
    +      RSplitMut(
    +          SplitMut(_iter_refs_expr, *this, ::sus::move(pred))),
    +      n);
     }
     
     #if 0
    @@ -587,7 +591,7 @@ constexpr RSplitNMut rsplitn_mut(
     /// Panics when `index >= len()`, meaning it always panics on empty slices.
     ::sus::Tuple, T&, SliceMut> select_nth_unstable_by(
         usize index,
    -    ::sus::fn::FnMutRef compare)
    +    ::sus::fn::FnMut auto compare)
         RETURN_REF noexcept {
       ::sus::check_with_message(
           index < len(), "partition_at_index index greater than length of slice");
    @@ -659,7 +663,7 @@ void sort() NO_RETURN_REF noexcept
     ///
     /// TODO: Rust's stable sort is O(n * log(n)), so this can be improved. It can
     /// also be constexpr?
    -void sort_by(::sus::fn::FnMutRef
    +void sort_by(::sus::fn::FnMut auto
                      compare) NO_RETURN_REF noexcept {
       if (len() > ::sus::num::usize(0u)) {
         std::stable_sort(as_mut_ptr(), as_mut_ptr() + len(),
    @@ -760,7 +764,7 @@ constexpr void sort_unstable() NO_RETURN_REF noexcept
     /// TODO: Rust's sort is unstable (i.e., may reorder equal elements), in-place
     /// (i.e., does not allocate), and O(n * log(n)) worst-case.
     constexpr void sort_unstable_by(
    -    ::sus::fn::FnMutRef compare)
    +    ::sus::fn::FnMut auto compare)
         NO_RETURN_REF noexcept {
       if (len() > 0u) {
         std::sort(as_mut_ptr(), as_mut_ptr() + len(),
    @@ -794,9 +798,9 @@ void sort_unstable_by_key(KeyFn f) NO_RETURN_REF noexcept {
     /// If the first element is matched, an empty slice will be the first item
     /// returned by the iterator. Similarly, if the last element in the slice is
     /// matched, an empty slice will be the last item returned by the iterator.
    -constexpr SplitMut split_mut(::sus::fn::FnMutRef pred)
    -    RETURN_REF noexcept {
    -  return SplitMut(_iter_refs_expr, *this, ::sus::move(pred));
    +template <::sus::fn::FnMut Pred>
    +constexpr SplitMut split_mut(Pred pred) RETURN_REF noexcept {
    +  return SplitMut(_iter_refs_expr, *this, ::sus::move(pred));
     }
     
     /// Divides one mutable slice into two at an index.
    @@ -865,9 +869,10 @@ split_first_mut() RETURN_REF noexcept {
     /// If the last element of the slice is matched, that element will be considered
     /// the terminator of the preceding slice. That slice will be the last item
     /// returned by the iterator.
    -constexpr SplitInclusiveMut split_inclusive_mut(
    -    ::sus::fn::FnMutRef pred) RETURN_REF noexcept {
    -  return SplitInclusiveMut(_iter_refs_expr, *this, ::sus::move(pred));
    +template <::sus::fn::FnMut Pred>
    +constexpr SplitInclusiveMut split_inclusive_mut(Pred pred)
    +    RETURN_REF noexcept {
    +  return SplitInclusiveMut(_iter_refs_expr, *this, ::sus::move(pred));
     }
     
     /// Returns the last and all the rest of the elements of the slice, or `None` if
    @@ -889,10 +894,11 @@ sus_pure constexpr ::sus::Option<::sus::Tuple>> split_last_mut()
     /// contained in the subslices.
     ///
     /// The last element returned, if any, will contain the remainder of the slice.
    -constexpr SplitNMut splitn_mut(
    -    usize n, ::sus::fn::FnMutRef pred) RETURN_REF noexcept {
    -  return SplitNMut(SplitMut(_iter_refs_expr, *this, ::sus::move(pred)),
    -                      n);
    +template <::sus::fn::FnMut Pred>
    +constexpr SplitNMut splitn_mut(usize n,
    +                                        Pred pred) RETURN_REF noexcept {
    +  return SplitNMut(
    +      SplitMut(_iter_refs_expr, *this, ::sus::move(pred)), n);
     }
     
     /// Returns a subslice with the `prefix` removed.
    diff --git a/sus/collections/array_unittest.cc b/sus/collections/array_unittest.cc
    index 911520415..bb6bce583 100644
    --- a/sus/collections/array_unittest.cc
    +++ b/sus/collections/array_unittest.cc
    @@ -265,7 +265,7 @@ TEST(Array, GetUnchecked) {
     }
     
     template 
    -concept HasGetMut = requires(T t, U u) { t.get_mut(u); };
    +concept HasGetMut = requires(T& t, const U& u) { t.get_mut(u); };
     
     // get_mut() is only available for mutable arrays.
     static_assert(!HasGetMut, usize>);
    @@ -289,7 +289,7 @@ TEST(Array, GetMut) {
     
     template 
     concept HasGetUncheckedMut =
    -    requires(T t, U u) { t.get_unchecked_mut(unsafe_fn, u); };
    +    requires(T& t, const U& u) { t.get_unchecked_mut(unsafe_fn, u); };
     
     // get_unchecked_mut() is only available for mutable arrays.
     static_assert(!HasGetUncheckedMut, usize>);
    diff --git a/sus/collections/iterators/split.h b/sus/collections/iterators/split.h
    index 1f7c5ed6e..22772db1e 100644
    --- a/sus/collections/iterators/split.h
    +++ b/sus/collections/iterators/split.h
    @@ -32,7 +32,7 @@ namespace __private {
     /// match a predicate function, splitting at most a fixed number of
     /// times.
     template  I>
    -class [[sus_trivial_abi]] GenericSplitN final
    +class GenericSplitN final
         : public ::sus::iter::IteratorBase, ItemT> {
      public:
       using Item = ItemT;
    @@ -66,8 +66,8 @@ class [[sus_trivial_abi]] GenericSplitN final
       I iter_;
       usize count_;
     
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(iter_),
    -                                  decltype(count_));
    +  sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn,
    +                                           decltype(iter_), decltype(count_));
     };
     
     }  // namespace __private
    @@ -76,9 +76,9 @@ class [[sus_trivial_abi]] GenericSplitN final
     /// function.
     ///
     /// This struct is created by the `split()` method on slices.
    -template 
    -class [[nodiscard]] [[sus_trivial_abi]] Split final
    -    : public ::sus::iter::IteratorBase,
    +template  Pred>
    +class [[nodiscard]] Split final
    +    : public ::sus::iter::IteratorBase,
                                            ::sus::collections::Slice> {
      public:
       // `Item` is a `Slice`.
    @@ -160,7 +160,7 @@ class [[nodiscard]] [[sus_trivial_abi]] Split final
       template  B>
       friend class __private::GenericSplitN;
       // Access to finish().
    -  template 
    +  template  APred>
       friend class RSplit;
     
       constexpr Option finish() noexcept {
    @@ -173,26 +173,27 @@ class [[nodiscard]] [[sus_trivial_abi]] Split final
       }
     
       constexpr Split(::sus::iter::IterRef ref, const Slice& values,
    -                  ::sus::fn::FnMutRef&& pred) noexcept
    +                  Pred&& pred) noexcept
           : ref_(::sus::move(ref)), v_(values), pred_(::sus::move(pred)) {}
     
       [[sus_no_unique_address]] ::sus::iter::IterRef ref_;
       Slice v_;
    -  ::sus::fn::FnMutRef pred_;
    +  Pred pred_;
       bool finished_ = false;
     
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(ref_),
    -                                  decltype(v_), decltype(pred_),
    -                                  decltype(finished_));
    +  sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn,
    +                                           decltype(ref_), decltype(v_),
    +                                           decltype(pred_),
    +                                           decltype(finished_));
     };
     
     /// An iterator over subslices separated by elements that match a predicate
     /// function.
     ///
     /// This struct is created by the `split_mut()` method on slices.
    -template 
    -class [[nodiscard]] [[sus_trivial_abi]] SplitMut final
    -    : public ::sus::iter::IteratorBase,
    +template  Pred>
    +class [[nodiscard]] SplitMut final
    +    : public ::sus::iter::IteratorBase,
                                            ::sus::collections::SliceMut> {
      public:
       // `Item` is a `SliceMut`.
    @@ -274,7 +275,7 @@ class [[nodiscard]] [[sus_trivial_abi]] SplitMut final
       template  B>
       friend class __private::GenericSplitN;
       // Access to finish().
    -  template 
    +  template >
       friend class RSplitMut;
     
       constexpr Option finish() noexcept {
    @@ -286,24 +287,19 @@ class [[nodiscard]] [[sus_trivial_abi]] SplitMut final
         }
       }
     
    -  static constexpr auto with(
    -      ::sus::iter::IterRef ref, const SliceMut& values,
    -      ::sus::fn::FnMutRef&& pred) noexcept {
    -    return SplitMut(::sus::move(ref), values, ::sus::move(pred));
    -  }
    -
       constexpr SplitMut(::sus::iter::IterRef ref, const SliceMut& values,
    -                     ::sus::fn::FnMutRef&& pred) noexcept
    +                     Pred&& pred) noexcept
           : ref_(::sus::move(ref)), v_(values), pred_(::sus::move(pred)) {}
     
       [[sus_no_unique_address]] ::sus::iter::IterRef ref_;
       SliceMut v_;
    -  ::sus::fn::FnMutRef pred_;
    +  Pred pred_;
       bool finished_ = false;
     
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(ref_),
    -                                  decltype(v_), decltype(pred_),
    -                                  decltype(finished_));
    +  sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn,
    +                                           decltype(ref_), decltype(v_),
    +                                           decltype(pred_),
    +                                           decltype(finished_));
     };
     
     /// An iterator over subslices separated by elements that match a predicate
    @@ -311,9 +307,9 @@ class [[nodiscard]] [[sus_trivial_abi]] SplitMut final
     /// of the subslice.
     ///
     /// This struct is created by the `split_inclusive()` method on slices.
    -template 
    -class [[nodiscard]] [[sus_trivial_abi]] SplitInclusive final
    -    : public ::sus::iter::IteratorBase,
    +template  Pred>
    +class [[nodiscard]] SplitInclusive final
    +    : public ::sus::iter::IteratorBase,
                                            ::sus::collections::Slice> {
      public:
       // `Item` is a `Slice`.
    @@ -398,9 +394,8 @@ class [[nodiscard]] [[sus_trivial_abi]] SplitInclusive final
       template 
       friend class Array;
     
    -  constexpr SplitInclusive(
    -      ::sus::iter::IterRef ref, const Slice& values,
    -      ::sus::fn::FnMutRef&& pred) noexcept
    +  constexpr SplitInclusive(::sus::iter::IterRef ref, const Slice& values,
    +                           Pred&& pred) noexcept
           : ref_(::sus::move(ref)),
             v_(values),
             pred_(::sus::move(pred)),
    @@ -408,12 +403,13 @@ class [[nodiscard]] [[sus_trivial_abi]] SplitInclusive final
     
       [[sus_no_unique_address]] ::sus::iter::IterRef ref_;
       Slice v_;
    -  ::sus::fn::FnMutRef pred_;
    +  Pred pred_;
       bool finished_;
     
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(ref_),
    -                                  decltype(v_), decltype(pred_),
    -                                  decltype(finished_));
    +  sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn,
    +                                           decltype(ref_), decltype(v_),
    +                                           decltype(pred_),
    +                                           decltype(finished_));
     };
     
     /// An iterator over subslices separated by elements that match a predicate
    @@ -421,9 +417,9 @@ class [[nodiscard]] [[sus_trivial_abi]] SplitInclusive final
     /// of the subslice.
     ///
     /// This struct is created by the `split_inclusive_mut()` method on slices.
    -template 
    -class [[nodiscard]] [[sus_trivial_abi]] SplitInclusiveMut final
    -    : public ::sus::iter::IteratorBase,
    +template  Pred>
    +class [[nodiscard]] SplitInclusiveMut final
    +    : public ::sus::iter::IteratorBase,
                                            ::sus::collections::SliceMut> {
      public:
       // `Item` is a `SliceMut`.
    @@ -509,15 +505,9 @@ class [[nodiscard]] [[sus_trivial_abi]] SplitInclusiveMut final
       template 
       friend class Array;
     
    -  static constexpr auto with(
    -      ::sus::iter::IterRef ref, const SliceMut& values,
    -      ::sus::fn::FnMutRef&& pred) noexcept {
    -    return SplitInclusiveMut(::sus::move(ref), values, ::sus::move(pred));
    -  }
    -
    -  constexpr SplitInclusiveMut(
    -      ::sus::iter::IterRef ref, const SliceMut& values,
    -      ::sus::fn::FnMutRef&& pred) noexcept
    +  constexpr SplitInclusiveMut(::sus::iter::IterRef ref,
    +                              const SliceMut& values,
    +                              Pred&& pred) noexcept
           : ref_(::sus::move(ref)),
             v_(values),
             pred_(::sus::move(pred)),
    @@ -525,25 +515,25 @@ class [[nodiscard]] [[sus_trivial_abi]] SplitInclusiveMut final
     
       [[sus_no_unique_address]] ::sus::iter::IterRef ref_;
       SliceMut v_;
    -  ::sus::fn::FnMutRef pred_;
    +  Pred pred_;
       bool finished_;
     
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(ref_),
    -                                  decltype(v_), decltype(pred_),
    -                                  decltype(finished_));
    +  sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn,
    +                                           decltype(ref_), decltype(v_),
    +                                           decltype(pred_),
    +                                           decltype(finished_));
     };
     
     /// An iterator over subslices separated by elements that match a predicate
     /// function, starting from the end of the slice.
     ///
     /// This struct is created by the `rsplit()` method on slices.
    -template 
    -class [[nodiscard]] [[sus_trivial_abi]] RSplit final
    -    : public ::sus::iter::IteratorBase,
    +template  Pred>
    +class [[nodiscard]] RSplit final
    +    : public ::sus::iter::IteratorBase,
                                            ::sus::collections::Slice> {
      public:
    -  // `Item` is a `Slice`.
    -  using Item = typename Split::Item;
    +  using Item = ::sus::collections::Slice;
     
       // sus::iter::Iterator trait.
       constexpr Option next() noexcept { return inner_.next_back(); }
    @@ -571,25 +561,25 @@ class [[nodiscard]] [[sus_trivial_abi]] RSplit final
     
       constexpr Option finish() noexcept { return inner_.finish(); }
     
    -  constexpr RSplit(Split&& split) noexcept
    +  constexpr RSplit(Split&& split) noexcept
           : inner_(::sus::move(split)) {}
     
    -  Split inner_;
    +  Split inner_;
     
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(inner_));
    +  sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn,
    +                                           decltype(inner_));
     };
     
     /// An iterator over the subslices of the vector which are separated by elements
     /// that match pred, starting from the end of the slice.
     ///
     /// This struct is created by the `rsplit_mut()` method on slices.
    -template 
    -class [[nodiscard]] [[sus_trivial_abi]] RSplitMut final
    -    : public ::sus::iter::IteratorBase,
    +template  Pred>
    +class [[nodiscard]] RSplitMut final
    +    : public ::sus::iter::IteratorBase,
                                            ::sus::collections::SliceMut> {
      public:
    -  // `Item` is a `SliceMut`.
    -  using Item = typename SplitMut::Item;
    +  using Item = ::sus::collections::SliceMut;
     
       // sus::iter::Iterator trait.
       constexpr Option next() noexcept { return inner_.next_back(); }
    @@ -617,25 +607,25 @@ class [[nodiscard]] [[sus_trivial_abi]] RSplitMut final
     
       Option finish() noexcept { return inner_.finish(); }
     
    -  constexpr RSplitMut(SplitMut&& split) noexcept
    +  constexpr RSplitMut(SplitMut&& split) noexcept
           : inner_(::sus::move(split)) {}
     
    -  SplitMut inner_;
    +  SplitMut inner_;
     
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(inner_));
    +  sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn,
    +                                           decltype(inner_));
     };
     
     /// An iterator over subslices separated by elements that match a predicate
     /// function, limited to a given number of splits.
     ///
     /// This struct is created by the `splitn()` method on slices.
    -template 
    -class [[nodiscard]] [[sus_trivial_abi]] SplitN final
    -    : public ::sus::iter::IteratorBase,
    +template  Pred>
    +class [[nodiscard]] SplitN final
    +    : public ::sus::iter::IteratorBase,
                                            ::sus::collections::Slice> {
      public:
    -  // `Item` is a `Slice`.
    -  using Item = typename Split::Item;
    +  using Item = ::sus::collections::Slice;
     
       // sus::iter::Iterator trait.
       constexpr Option next() noexcept { return inner_.next(); }
    @@ -654,25 +644,25 @@ class [[nodiscard]] [[sus_trivial_abi]] SplitN final
       template 
       friend class Array;
     
    -  constexpr SplitN(Split split, usize n) noexcept
    +  constexpr SplitN(Split split, usize n) noexcept
           : inner_(::sus::move(split), n) {}
     
    -  __private::GenericSplitN, Split> inner_;
    +  __private::GenericSplitN, Split> inner_;
     
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(inner_));
    +  sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn,
    +                                           decltype(inner_));
     };
     
     /// An iterator over mutable subslices separated by elements that match a
     /// predicate function, limited to a given number of splits.
     ///
     /// This struct is created by the `splitn_mut()` method on slices.
    -template 
    -class [[nodiscard]] [[sus_trivial_abi]] SplitNMut final
    -    : public ::sus::iter::IteratorBase,
    +template  Pred>
    +class [[nodiscard]] SplitNMut final
    +    : public ::sus::iter::IteratorBase,
                                            ::sus::collections::SliceMut> {
      public:
    -  // `Item` is a `SliceMut`.
    -  using Item = typename SplitMut::Item;
    +  using Item = ::sus::collections::SliceMut;
     
       // sus::iter::Iterator trait.
       constexpr Option next() noexcept { return inner_.next(); }
    @@ -691,12 +681,13 @@ class [[nodiscard]] [[sus_trivial_abi]] SplitNMut final
       template 
       friend class Array;
     
    -  constexpr SplitNMut(SplitMut split, usize n) noexcept
    +  constexpr SplitNMut(SplitMut split, usize n) noexcept
           : inner_(::sus::move(split), n) {}
     
    -  __private::GenericSplitN, SplitMut> inner_;
    +  __private::GenericSplitN, SplitMut> inner_;
     
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(inner_));
    +  sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn,
    +                                           decltype(inner_));
     };
     
     /// An iterator over subslices separated by elements that match a predicate
    @@ -704,13 +695,12 @@ class [[nodiscard]] [[sus_trivial_abi]] SplitNMut final
     /// slice.
     ///
     /// This struct is created by the `rsplitn()` method on slices.
    -template 
    -class [[nodiscard]] [[sus_trivial_abi]] RSplitN final
    -    : public ::sus::iter::IteratorBase,
    +template  Pred>
    +class [[nodiscard]] RSplitN final
    +    : public ::sus::iter::IteratorBase,
                                            ::sus::collections::Slice> {
      public:
    -  // `Item` is a `Slice`.
    -  using Item = typename RSplit::Item;
    +  using Item = ::sus::collections::Slice;
     
       // sus::iter::Iterator trait.
       constexpr Option next() noexcept { return inner_.next(); }
    @@ -729,12 +719,13 @@ class [[nodiscard]] [[sus_trivial_abi]] RSplitN final
       template 
       friend class Array;
     
    -  constexpr RSplitN(RSplit split, usize n) noexcept
    +  constexpr RSplitN(RSplit split, usize n) noexcept
           : inner_(::sus::move(split), n) {}
     
    -  __private::GenericSplitN, RSplit> inner_;
    +  __private::GenericSplitN, RSplit> inner_;
     
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(inner_));
    +  sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn,
    +                                           decltype(inner_));
     };
     
     /// An iterator over subslices separated by elements that match a predicate
    @@ -742,13 +733,13 @@ class [[nodiscard]] [[sus_trivial_abi]] RSplitN final
     /// slice.
     ///
     /// This struct is created by the rsplitn_mut method on slices.
    -template 
    -class [[nodiscard]] [[sus_trivial_abi]] RSplitNMut final
    -    : public ::sus::iter::IteratorBase,
    +template  Pred>
    +class [[nodiscard]] RSplitNMut final
    +    : public ::sus::iter::IteratorBase,
                                            ::sus::collections::SliceMut> {
      public:
       // `Item` is a `SliceMut`.
    -  using Item = typename RSplitMut::Item;
    +  using Item = ::sus::collections::SliceMut;
     
       // sus::iter::Iterator trait.
       constexpr Option next() noexcept { return inner_.next(); }
    @@ -767,12 +758,13 @@ class [[nodiscard]] [[sus_trivial_abi]] RSplitNMut final
       template 
       friend class Array;
     
    -  constexpr RSplitNMut(RSplitMut split, usize n) noexcept
    +  constexpr RSplitNMut(RSplitMut split, usize n) noexcept
           : inner_(::sus::move(split), n) {}
     
    -  __private::GenericSplitN, RSplitMut> inner_;
    +  __private::GenericSplitN, RSplitMut> inner_;
     
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(inner_));
    +  sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn,
    +                                           decltype(inner_));
     };
     
     }  // namespace sus::collections
    diff --git a/sus/collections/slice.h b/sus/collections/slice.h
    index 7da030971..2ef410dfa 100644
    --- a/sus/collections/slice.h
    +++ b/sus/collections/slice.h
    @@ -28,7 +28,6 @@
     #include "sus/collections/join.h"
     #include "sus/construct/default.h"
     #include "sus/fn/fn_concepts.h"
    -#include "sus/fn/fn_ref.h"
     #include "sus/iter/iterator_defn.h"
     #include "sus/iter/iterator_ref.h"
     #include "sus/lib/__private/forward_decl.h"
    diff --git a/sus/collections/slice_unittest.cc b/sus/collections/slice_unittest.cc
    index 6f291c761..deb9279a2 100644
    --- a/sus/collections/slice_unittest.cc
    +++ b/sus/collections/slice_unittest.cc
    @@ -105,7 +105,7 @@ TEST(Slice, Get) {
     }
     
     template 
    -concept HasGetMut = requires(T t, U u) { t.get_mut(u); };
    +concept HasGetMut = requires(T& t, const U& u) { t.get_mut(u); };
     
     // get_mut() is only available for mutable slices. A "const" mutable slice can
     // still give mutable access as the mutability is encoded in the type.
    @@ -138,7 +138,7 @@ TEST(Slice, GetUnchecked) {
     
     template 
     concept HasGetUncheckedMut =
    -    requires(T t, U u) { t.get_unchecked_mut(unsafe_fn, u); };
    +    requires(T& t, const U& u) { t.get_unchecked_mut(unsafe_fn, u); };
     
     // get_unchecked_mut() is only available for mutable slices of mutable types.
     static_assert(!HasGetUncheckedMut, usize>);
    @@ -2563,8 +2563,8 @@ TEST(SliceMut, FillWith) {
       v1["2..4"_r].fill_with(f);
       EXPECT_EQ(v1[0u], 6);
       EXPECT_EQ(v1[1u], 7);
    -  EXPECT_EQ(v1[2u], 10);
    -  EXPECT_EQ(v1[3u], 11);
    +  EXPECT_EQ(v1[2u], 6);
    +  EXPECT_EQ(v1[3u], 7);
     }
     
     TEST(SliceMut, FillWithDefault) {
    diff --git a/sus/collections/vec.h b/sus/collections/vec.h
    index 5f720bc14..befab4a48 100644
    --- a/sus/collections/vec.h
    +++ b/sus/collections/vec.h
    @@ -34,7 +34,6 @@
     #include "sus/collections/iterators/vec_iter.h"
     #include "sus/collections/slice.h"
     #include "sus/fn/fn_concepts.h"
    -#include "sus/fn/fn_ref.h"
     #include "sus/iter/adaptors/by_ref.h"
     #include "sus/iter/adaptors/enumerate.h"
     #include "sus/iter/adaptors/take.h"
    diff --git a/sus/collections/vec_unittest.cc b/sus/collections/vec_unittest.cc
    index 84cdd6c61..0e901d2a5 100644
    --- a/sus/collections/vec_unittest.cc
    +++ b/sus/collections/vec_unittest.cc
    @@ -211,7 +211,7 @@ TEST(Vec, GetMut) {
     }
     
     template 
    -concept HasGetMut = requires(T t, U u) { t.get_mut(u); };
    +concept HasGetMut = requires(T& t, const U& u) { t.get_mut(u); };
     
     // get_mut() is only available for mutable Vec.
     static_assert(!HasGetMut, usize>);
    @@ -233,7 +233,7 @@ TEST(Vec, GetUncheckedMut) {
     
     template 
     concept HasGetUncheckedMut =
    -    requires(T t, U u) { t.get_unchecked_mut(unsafe_fn, u); };
    +    requires(T& t, const U& u) { t.get_unchecked_mut(unsafe_fn, u); };
     
     // get_unchecked_mut() is only available for mutable Vec.
     static_assert(!HasGetUncheckedMut, usize>);
    diff --git a/sus/construct/__private/into_ref.h b/sus/construct/__private/into_ref.h
    index aeec43836..df267e22b 100644
    --- a/sus/construct/__private/into_ref.h
    +++ b/sus/construct/__private/into_ref.h
    @@ -17,23 +17,24 @@
     #pragma once
     
     #include "sus/construct/from.h"
    +#include "sus/mem/forward.h"
     
     namespace sus::construct ::__private {
     
     template 
     struct IntoRef final {
       [[nodiscard]] constexpr IntoRef(FromType&& from) noexcept
    -      : from_(static_cast(from)) {}
    +      : from_(::sus::forward(from)) {}
     
    -  template > ToType>
    +  template > ToType>
       constexpr operator ToType() && noexcept {
         return static_cast(from_);
       }
     
       template <::sus::construct::From ToType>
    -    requires(!std::same_as, ToType>)
    +    requires(!std::same_as, ToType>)
       constexpr operator ToType() && noexcept {
    -    return ToType::from(static_cast(from_));
    +    return ToType::from(::sus::forward(from_));
       }
     
       // Doesn't copy or move. `IntoRef` should only be used as a temporary.
    diff --git a/sus/construct/into.h b/sus/construct/into.h
    index eb8d882d7..5789844df 100644
    --- a/sus/construct/into.h
    +++ b/sus/construct/into.h
    @@ -29,38 +29,44 @@
     
     namespace sus::construct {
     
    -/// A concept that declares `FromType` can be converted to `ToType` through the
    -/// [`From`]($sus::construct::From) concept or through an identity
    -/// transformation.
    +/// A concept that declares `FromType` can be converted to `ToType`.
     ///
    -/// When true, `ToType::from(FromType)` can be used to construct `ToType`,
    -/// or `ToType` is the same as `FromType`.
    +/// When true, the conversion can be done in one of three ways:
    +/// * `ToType::from(FromType)` can be used to construct `ToType`, which is the
    +///   preferred way to write conversions. It avoids any accidental conversions
    +///   as it does not have an ambiguous appearance with a copy or move.
    +/// * `ToType` is the same as `FromType`, in which case a reference to the
    +///   object is passed along, and no construction or conversion happens.
     ///
    -/// This is the inverse of the [`From`]($sus::construct::From) concept, meant to
    -/// be used on methods that want to receive any type and which will explicitly
    -/// convert what they are given type.
    +/// This is the inverse direction from the [`From`]($sus::construct::From)
    +/// concept, while also a broader generalization. It is meant to
    +/// be used on methods that want to receive any type that can explicitly be
    +/// converted to a specific type.
     ///
     /// This concept is not implementable directly, as it's satisfied for `T` by
     /// implementing the [`From`]($sus::construct::From) concept on a different
    -/// type. It is only possible to satisfy this concept for `ToType` that is not a
    +/// type.
    +/// It is only possible to satisfy this concept for a `ToType` that is not a
     /// reference, as it needs to be able to construct `ToType`.
     ///
     /// # Templates
     ///
     /// To receive [`into()`]($sus::construct::into) correctly for a templated
     /// function argument:
    -/// * Avoid
    -/// [`std::same_as`](https://en.cppreference.com/w/cpp/concepts/same_as), use
    -/// [`std::convertible_to`](https://en.cppreference.com/w/cpp/concepts/convertible_to)
    -/// instead, as this will
    -///   accept the marker type returned from [into]($sus::construct::into).
    +/// * Avoid [`std::same_as`](
    +///   https://en.cppreference.com/w/cpp/concepts/same_as), use
    +///   [`std::convertible_to`](
    +///   https://en.cppreference.com/w/cpp/concepts/convertible_to) instead, as
    +///   this will accept the marker type returned from
    +///   [into]($sus::construct::into).
     /// * If the argument is a fixed dependent type, like the following:
     ///   ```
     ///   template >
     ///   void f(In i) {}
     ///   ```
     ///   Insert an extra template parameter that uses
    -///   [`std::convertible_to`](https://en.cppreference.com/w/cpp/concepts/convertible_to)
    +///   [`std::convertible_to`](
    +///   https://en.cppreference.com/w/cpp/concepts/convertible_to)
     ///   and the template type, such as:
     ///   ```
     ///   template , std::convertible_to In>
    @@ -141,12 +147,14 @@ concept TryInto = ::sus::construct::TryFrom ||
     
     /// Attempts to convert from the given value to a `ToType`.
     ///
    -/// Unlike `into()`, this function can not use type deduction to determine the
    -/// receiving type as it needs to determine the Result type and allow the caller
    -/// the chance to handle the error condition.
    +/// Unlike [`into()`]($sus::construct::into), this function can not use type
    +/// deduction to determine the
    +/// receiving type as it needs to determine the [`Result`]($sus::result::Result)
    +/// type and allow the caller the chance to handle the error condition.
     ///
     /// The `TryFrom` concept requires a `try_from()` method that returns a
    -/// `Result`. That `Result` will be the return type of this function.
    +/// [`Result`]($sus::result::Result). That [`Result`]($sus::result::Result)
    +/// will be the return type of this function.
     ///
     /// # Example
     /// ```
    diff --git a/sus/construct/transmogrify.h b/sus/construct/transmogrify.h
    index 2d74f7c15..20ae16ac4 100644
    --- a/sus/construct/transmogrify.h
    +++ b/sus/construct/transmogrify.h
    @@ -61,13 +61,18 @@ struct TransmogrifyImpl {
     /// conversion may truncate or extend `F` in order to do the conversion to `T`.
     ///
     /// This operation is also commonly known as type casting, or type coercion. The
    -/// conversion to `T` can be done by calling `sus::mog(from)`.
    +/// conversion to `T` can be done by calling
    +/// [`sus::mog(from)`]($sus::construct::mog).
     ///
     /// The conversion is defined for the identity conversion where both the input
    -/// and output are the same type, if the type is `Copy`, in which case the input
    -/// is copied and returned. As Transmogrification is meant to be a cheap
    -/// conversion, primarily for primitive types, it does not support `Clone`
    -/// types, and `sus::construct::Into` should be used in more complex cases.
    +/// and output are the same type, if the type is [`Copy`]($sus::mem::Copy), in
    +//  which case the input is copied and returned.
    +/// As Transmogrification is meant to be a cheap
    +/// conversion, primarily for primitive types, it does not support
    +/// [`Clone`]($sus::mem::Clone) types, and [`Into`]($sus::construct::Into)
    +/// should be used in more complex cases.
    +///
    +/// # Casting numeric types
     ///
     /// For numeric and primitive types, `Transmogrify` is defined to provide a
     /// mechanism like `static_cast` but it is much safer than `static_cast`
    @@ -76,33 +81,34 @@ struct TransmogrifyImpl {
     /// * Casting from a float to an integer will perform a static_cast, which
     ///   rounds the float towards zero, except:
     ///   * `NAN` will return 0.
    -///   * Values larger than the maximum integer value, including `f32::INFINITY`,
    +///   * Values larger than the maximum integer value, including
    +///     [`f32::INFINITY`]($sus::num::f32::INFINITY),
     ///     will saturate to the maximum value of the integer type.
     ///   * Values smaller than the minimum integer value, including
    -///     `f32::NEG_INFINITY`, will saturate to the minimum value of the integer
    -///     type.
    -/// * Casting from an integer to a float will perform a static_cast, which
    +///     [`f32::NEG_INFINITY`]($sus::num::f32::NEG_INFINITY), will saturate to
    +///     the minimum value of the integer type.
    +/// * Casting from an integer to a float will perform a `static_cast`, which
     ///   converts to the nearest floating point value. The rounding direction for
     ///   values that land between representable floating point values is
     ///   implementation defined (per C++20 Section 7.3.10).
    -/// * Casting from an `f32` (or `float`) to an `f64` (or `double`) preserves the
    +/// * Casting from an [`f32`]($sus::num::f32) (or `float`) to an
    +///   [`f64`]($sus::num::f64) (or `double`) preserves the
     ///   value unchanged.
    -/// * Casting from an `f64` (or `double`) to an `f32` (or float) performs the
    -///   same action as a static_cast if the value is in range for f32, otherwise:
    +/// * Casting from an [`f64`]($sus::num::f64) (or `double`) to an
    +///   [`f32`]($sus::num::f32) (or float) performs the same action as a
    +///   `static_cast` if the value is in range for [`f32`]($sus::num::f32),
    +///   otherwise:
     ///   * `NAN` will return a `NAN`.
    -///   * Values outside of f32's range will return `f32::INFINITY` or
    -///     `f32::NEG_INFINITY` for positive and negative values respectively.
    -/// * Casting to and from `std::byte` produces the same values as casting to and
    -///   from `u8`.
    +///   * Values outside of [`f32`]($sus::num::f32)'s range will return
    +///     [`f32::INFINITY`]($sus::num::f32::INFINITY) or
    +///     [`f32::NEG_INFINITY`]($sus::num::f32::NEG_INFINITY) for positive and
    +///     negative values respectively.
    +/// * Casting to and from [`std::byte`](
    +///   https://en.cppreference.com/w/cpp/types/byte) produces the same values
    +///   as casting to and from [`u8`]($sus::num::u8).
     ///
     /// These conversions are all defined in `sus/num/types.h`.
     ///
    -/// The transmogrifier is one of three of the most complicated inventions. The
    -/// other two are the [Cerebral
    -/// Enhance-O-Tron](https://calvinandhobbes.fandom.com/wiki/Cerebral_Enhance-O-Tron),
    -/// and the [Transmogrifier
    -/// Gun](https://calvinandhobbes.fandom.com/wiki/Transmogrifier_Gun).
    -///
     /// # Extending to other types
     ///
     /// Types can participate in defining their transmogrification strategy by
    @@ -112,6 +118,14 @@ struct TransmogrifyImpl {
     ///
     /// The `Transmogrify` specialization needs a static method `mog_from()` that
     /// receives `const From&` and returns `To`.
    +///
    +/// # Lore
    +///
    +/// The transmogrifier is one of three of the most complicated inventions. The
    +/// other two are the [Cerebral
    +/// Enhance-O-Tron](https://calvinandhobbes.fandom.com/wiki/Cerebral_Enhance-O-Tron),
    +/// and the [Transmogrifier
    +/// Gun](https://calvinandhobbes.fandom.com/wiki/Transmogrifier_Gun).
     template 
     concept Transmogrify = requires(const From& from) {
       {
    @@ -126,15 +140,19 @@ concept Transmogrify = requires(const From& from) {
     /// memory unsafety if used incorrectly. This behaves like `static_cast()`
     /// but without Undefined Behaviour.
     ///
    -/// The `mog` operation is supported for types `To` and `From` that satisfy
    -/// `Transmogrify`.
    +/// The [`mog`]($sus::construct::mog) operation is supported for types `To` and
    +/// `From` that satisfy [`Transmogrify`](
    +/// $sus::construct::Transmogrify).
     ///
     /// To convert between types while ensuring the values are preserved, use
    -/// `sus::construct::Into` or `sus::construct::TryInto`. Usually prefer using
    -/// `sus::into(x)` or `sus::try_into(x)` over `sus::mog(x)` as most code
    +/// [`Into`]($sus::construct::Into) or [`TryInto`]($sus::construct::TryInto).
    +/// Usually prefer using [`sus::into(x)`]($sus::construct::into) or
    +/// [`sus::try_into(x)`]($sus::construct::try_into) over
    +/// [`sus::mog(x)`]($sus::construct::mog) as most code
     /// should preserve values across type transitions.
     ///
    -/// See `Transmogrify` for how numeric and primitive values are converted.
    +/// See [`Transmogrify`]($sus::construct::Transmogrify) for how numeric and
    +/// primitive values are converted.
     ///
     /// # Examples
     ///
    diff --git a/sus/error/error.h b/sus/error/error.h
    index f739f85d0..1179e4c71 100644
    --- a/sus/error/error.h
    +++ b/sus/error/error.h
    @@ -15,6 +15,7 @@
     #pragma once
     
     #include "fmt/core.h"
    +#include "sus/boxed/dyn.h"
     #include "sus/macros/lifetimebound.h"
     #include "sus/option/option.h"
     
    @@ -224,6 +225,9 @@ concept HasErrorSource = requires(const T& t) {
     /// single type, as does passing error types through virtual methods or dylib
     /// ABI boundaries.
     ///
    +/// See [`DynConcept`]($sus::boxed::DynConcept) for more on type erasure of
    +/// [`Error`]($sus::error::Error) types.
    +///
     /// ## Opaque erasure
     /// When an application just wants to return an error without exposing the
     /// actual type behind it, use the [`DynError`]($sus::error::DynError) type.
    @@ -239,7 +243,7 @@ concept HasErrorSource = requires(const T& t) {
     /// `error` that satisfies [`Error`]($sus::error::Error).
     ///
     /// This is similar to
    -/// `&dyn Error` when working with the Rust
    +/// `Box` when working with the Rust
     /// [`Error`](https://doc.rust-lang.org/stable/std/error/trait.Error.html)
     /// trait. However with `DynError`, the error type can be printed/displayed but
     /// no further information can be extracted from the error. Nonetheless this is
    @@ -419,8 +423,13 @@ concept Error = requires(const T& t) {
       };
     };
     
    +template 
    +struct DynErrorTyped;
    +
     /// A type-erased [`Error`]($sus::error::Error) object.
     ///
    +/// `DynError` also satisfies [`Error`]($sus::error::Error) itself.
    +///
     /// Using this allows the error type to be placed in heap-allocated smart
     /// pointers without templates, and thus without knowing the concrete type.
     /// For example a `void foo(Box)` function can work with any
    @@ -432,16 +441,30 @@ concept Error = requires(const T& t) {
     /// and it can not be moved similar to
     /// [`Pin`](https://doc.rust-lang.org/std/pin/struct.Pin.html) types in
     /// Rust.
    +///
    +/// See [`DynConcept`]($sus::boxed::DynConcept) for more on type erasure of
    +/// concept-satisfying types.
     struct DynError {
       /// Forwards to the [`Error`]($sus::error::Error) implementation of `E`.
       virtual std::string display() const noexcept = 0;
       /// Forwards to the [`Error`]($sus::error::Error) implementation of `E`.
       virtual sus::Option source() const noexcept = 0;
     
    +  // `DynConcept` machinery for type-erasing the `Error` concept.
    +
    +  /// #[doc.hidden]
       constexpr DynError() = default;
    +  /// #[doc.hidden]
       constexpr virtual ~DynError() = default;
       DynError(DynError&&) = delete;
    +  /// #[doc.hidden]
       DynError&& operator=(DynError&&) = delete;
    +  /// #[doc.hidden]
    +  template 
    +  static constexpr bool SatisfiesConcept = Error;
    +  /// #[doc.hidden]
    +  template 
    +  using DynTyped = DynErrorTyped;
     };
     
     /// Gets a string describing the `error` from an [`Error`]($sus::error::Error)
    @@ -463,10 +486,12 @@ constexpr inline sus::Option error_source(
       }
     }
     
    -/// The wrapper around an [`Error`]($sus::error::Error) object that allows it
    -/// to be type-erased as [`DynError`]($sus::error::DynError).
    -template 
    -struct DynErrorTyped : public DynError {
    +/// The type-aware subclass of `DynError` for type-erasing an `Error` concept
    +/// type through `DynConcept`.
    +///
    +/// #[doc.hidden]
    +template 
    +struct DynErrorTyped final : public DynError {
       std::string display() const noexcept override {
         return error_display(error_);
       }
    @@ -474,15 +499,10 @@ struct DynErrorTyped : public DynError {
         return error_source(error_);
       }
     
    -  constexpr DynErrorTyped(E&& error) : error_(::sus::move(error)) {}
    -  constexpr ~DynErrorTyped() override = default;
    -
    -  /// Unwraps and returns the inner error type `E`, discarding the
    -  /// `DynErrorTyped`.
    -  constexpr E into_inner() && noexcept { return ::sus::move(error_); }
    +  constexpr DynErrorTyped(Store&& c) : error_(std::forward(c)) {}
     
      private:
    -  E error_;
    +  Store error_;
     };
     
     }  // namespace sus::error
    diff --git a/sus/error/error_unittest.cc b/sus/error/error_unittest.cc
    index 0f5998112..e1f286255 100644
    --- a/sus/error/error_unittest.cc
    +++ b/sus/error/error_unittest.cc
    @@ -88,6 +88,13 @@ static_assert(sus::error::Error);
     
     namespace {
     using sus::error::Error;
    +using sus::error::DynError;
    +
    +// Tests that DynError functions as a DynConcept.
    +static_assert(sus::boxed::DynConcept);
    +static_assert(sus::boxed::DynConcept);
    +static_assert(sus::boxed::DynConcept);
    +static_assert(sus::boxed::DynConcept);
     
     TEST(Error, Example_ToString) {
       auto err = u32::try_from(-1).unwrap_err();
    @@ -96,7 +103,7 @@ TEST(Error, Example_ToString) {
     
     TEST(Error, Example_Result) {
       auto f =
    -      [](i32 i) -> sus::result::Result> {
    +      [](i32 i) -> sus::result::Result> {
         if (i > 10) return sus::err(sus::into(ErrorReason::SomeReason));
         if (i < -10) return sus::err(sus::into(ErrorString("too low")));
         return sus::ok();
    @@ -145,11 +152,11 @@ TEST(Error, Source) {
       auto super_error = SuperError{.source = sus::into(SuperErrorSideKick())};
       decltype(auto) source = sus::error::error_source(super_error);
       static_assert(
    -      std::same_as>);
    +      std::same_as>);
       EXPECT_EQ(source.is_some(), true);
       decltype(auto) inner_source = sus::error::error_source(source.as_value());
       static_assert(std::same_as>);
    +                             sus::Option>);
       EXPECT_EQ(inner_source.is_some(), false);
     
       EXPECT_EQ(sus::error::error_display(*source), "SuperErrorSideKick is here!");
    diff --git a/sus/fn/__private/callable_types.h b/sus/fn/__private/callable_types.h
    deleted file mode 100644
    index 1d02212c3..000000000
    --- a/sus/fn/__private/callable_types.h
    +++ /dev/null
    @@ -1,81 +0,0 @@
    -// Copyright 2023 Google LLC
    -//
    -// Licensed under the Apache License, Version 2.0 (the "License");
    -// you may not use this file except in compliance with the License.
    -// You may obtain a copy of the License at
    -//
    -//     https://www.apache.org/licenses/LICENSE-2.0
    -//
    -// Unless required by applicable law or agreed to in writing, software
    -// distributed under the License is distributed on an "AS IS" BASIS,
    -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    -// See the License for the specific language governing permissions and
    -// limitations under the License.
    -
    -// IWYU pragma: private
    -// IWYU pragma: friend "sus/.*"
    -#pragma once
    -
    -#include 
    -#include 
    -#include 
    -
    -#include "sus/mem/forward.h"
    -#include "sus/mem/move.h"
    -
    -namespace sus::fn::__private {
    -
    -/// Whether a functor `F` is a function pointer that is callable with `Args...`
    -/// and will return a value that can be stored as `R`.
    -template 
    -concept FunctionPointer =
    -    std::is_pointer_v> && requires(F f, Args... args) {
    -      { std::invoke(*f, args...) } -> std::convertible_to;
    -    };
    -
    -/// Whether a functor `T` is a function pointer.
    -template 
    -concept IsFunctionPointer =
    -    std::is_pointer_v && std::is_function_v>;
    -
    -/// Whether a functor `T` can convert to a function pointer, typically this
    -/// means it's a captureless lambda.
    -template 
    -concept ConvertsToFunctionPointer = requires(F f) {
    -  { +f } -> IsFunctionPointer;
    -};
    -
    -/// Whether a functor `F` is a callable object (with an `operator()`) that is
    -/// once-callable as an rvalue with `Args...` and will return a value that can
    -/// be stored as `R`.
    -template 
    -concept CallableOnceMut =
    -    !FunctionPointer && requires(F&& f, Args... args) {
    -      {
    -        std::invoke(::sus::move(f), ::sus::forward(args)...)
    -      } -> std::convertible_to;
    -    };
    -
    -/// Whether a functor `F` is a callable object (with an `operator()`) that is
    -/// mutable-callable as an lvalue with `Args...` and will return a value that
    -/// can be stored as `R`.
    -template 
    -concept CallableMut =
    -    !FunctionPointer && requires(F& f, Args... args) {
    -      {
    -        std::invoke(f, ::sus::forward(args)...)
    -      } -> std::convertible_to;
    -    };
    -
    -/// Whether a functor `F` is a callable object (with an `operator()`) that is
    -/// const-callable with `Args...` and will return a value that can be stored as
    -/// `R`.
    -template 
    -concept CallableConst =
    -    !FunctionPointer && requires(const F& f, Args... args) {
    -      {
    -        std::invoke(f, ::sus::forward(args)...)
    -      } -> std::convertible_to;
    -    };
    -
    -}  // namespace sus::fn::__private
    diff --git a/sus/fn/__private/fn_box_storage.h b/sus/fn/__private/fn_box_storage.h
    deleted file mode 100644
    index c73e1b00d..000000000
    --- a/sus/fn/__private/fn_box_storage.h
    +++ /dev/null
    @@ -1,77 +0,0 @@
    -// Copyright 2022 Google LLC
    -//
    -// Licensed under the Apache License, Version 2.0 (the "License");
    -// you may not use this file except in compliance with the License.
    -// You may obtain a copy of the License at
    -//
    -//     https://www.apache.org/licenses/LICENSE-2.0
    -//
    -// Unless required by applicable law or agreed to in writing, software
    -// distributed under the License is distributed on an "AS IS" BASIS,
    -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    -// See the License for the specific language governing permissions and
    -// limitations under the License.
    -
    -// IWYU pragma: private
    -// IWYU pragma: friend "sus/.*"
    -#pragma once
    -
    -#include 
    -
    -#include "sus/option/option.h"
    -
    -namespace sus::fn::__private {
    -
    -struct FnBoxStorageVtableBase {};
    -
    -struct FnBoxStorageBase {
    -  virtual ~FnBoxStorageBase() = default;
    -
    -  // Should be to a static lifetime pointee.
    -  Option vtable;
    -};
    -
    -template 
    -struct FnBoxStorageVtable final : public FnBoxStorageVtableBase {
    -  R (*call_once)(__private::FnBoxStorageBase&&, CallArgs...);
    -  R (*call_mut)(__private::FnBoxStorageBase&, CallArgs...);
    -  R (*call)(const __private::FnBoxStorageBase&, CallArgs...);
    -};
    -
    -template 
    -class FnBoxStorage final : public FnBoxStorageBase {
    - public:
    -  ~FnBoxStorage() override = default;
    -
    -  constexpr FnBoxStorage(F&& callable)
    -    requires(!(std::is_member_function_pointer_v> ||
    -               std::is_member_object_pointer_v>))
    -      : callable_(::sus::move(callable)) {}
    -  constexpr FnBoxStorage(F ptr)
    -    requires(std::is_member_function_pointer_v ||
    -             std::is_member_object_pointer_v)
    -      : callable_(ptr) {}
    -
    -  template 
    -  static R call(const FnBoxStorageBase& self_base, CallArgs... callargs) {
    -    const auto& self = static_cast(self_base);
    -    return std::invoke(self.callable_, forward(callargs)...);
    -  }
    -
    -  template 
    -  static R call_mut(FnBoxStorageBase& self_base, CallArgs... callargs) {
    -    auto& self = static_cast(self_base);
    -    return std::invoke(self.callable_, forward(callargs)...);
    -  }
    -
    -  template 
    -  static R call_once(FnBoxStorageBase&& self_base, CallArgs... callargs) {
    -    auto&& self = static_cast(self_base);
    -    return std::invoke(::sus::move(self.callable_),
    -                       forward(callargs)...);
    -  }
    -
    -  F callable_;
    -};
    -
    -}  // namespace sus::fn::__private
    diff --git a/sus/fn/__private/fn_ref_invoker.h b/sus/fn/__private/fn_ref_invoker.h
    deleted file mode 100644
    index 0a2ba540b..000000000
    --- a/sus/fn/__private/fn_ref_invoker.h
    +++ /dev/null
    @@ -1,78 +0,0 @@
    -// Copyright 2023 Google LLC
    -//
    -// Licensed under the Apache License, Version 2.0 (the "License");
    -// you may not use this file except in compliance with the License.
    -// You may obtain a copy of the License at
    -//
    -//     https://www.apache.org/licenses/LICENSE-2.0
    -//
    -// Unless required by applicable law or agreed to in writing, software
    -// distributed under the License is distributed on an "AS IS" BASIS,
    -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    -// See the License for the specific language governing permissions and
    -// limitations under the License.
    -
    -// IWYU pragma: private
    -// IWYU pragma: friend "sus/.*"
    -#pragma once
    -
    -#include 
    -
    -#include "sus/mem/forward.h"
    -#include "sus/mem/move.h"
    -
    -namespace sus::fn::__private {
    -
    -union Storage {
    -  void (*fnptr)();
    -  void* object;
    -};
    -
    -/// Functions to call a functor `F` that is stored in `Storage`. The choice of
    -/// function encodes which member of `Storage` holds the functor.
    -template 
    -struct Invoker {
    -  /// Calls the `F` in `Storage`, allowing mutable overlaods, when it is a
    -  /// function pointer.
    -  template 
    -  static R fnptr_call_mut(const union Storage& s, Args... args) {
    -    F f = reinterpret_cast(s.fnptr);
    -    return std::invoke(*f, ::sus::forward(args)...);
    -  }
    -
    -  /// Calls the `F` in `Storage`, as an lvalue, when it is a callable object.
    -  template 
    -  static R object_call_mut(const union Storage& s, Args... args) {
    -    F& f = *static_cast(s.object);
    -    return std::invoke(f, ::sus::forward(args)...);
    -  }
    -
    -  /// Calls the `F` in `Storage`, as an rvalue, when it is a callable object.
    -  template 
    -  static R object_call_once(const union Storage& s, Args... args) {
    -    F& f = *static_cast(s.object);
    -    return std::invoke(::sus::move(f), ::sus::forward(args)...);
    -  }
    -
    -  /// Calls the `F` in `Storage`, allowing only const overloads, when it is a
    -  /// function pointer.
    -  template 
    -  static R fnptr_call_const(const union Storage& s, Args... args) {
    -    const F f = reinterpret_cast(s.fnptr);
    -    return std::invoke(*f, ::sus::forward(args)...);
    -  }
    -
    -  /// Calls the `F` in `Storage`, as a const object, when it is a callable
    -  /// object.
    -  template 
    -  static R object_call_const(const union Storage& s, Args... args) {
    -    const F& f = *static_cast(s.object);
    -    return std::invoke(f, ::sus::forward(args)...);
    -  }
    -};
    -
    -/// A function pointer type that matches all the invoke functions the `Invoker`.
    -template 
    -using InvokeFnPtr = R (*)(const union Storage& s, CallArgs... args);
    -
    -}  // namespace sus::fn::__private
    diff --git a/sus/fn/__private/signature.h b/sus/fn/__private/signature.h
    index 9ffc76491..45cd1e66b 100644
    --- a/sus/fn/__private/signature.h
    +++ b/sus/fn/__private/signature.h
    @@ -88,7 +88,7 @@ struct InvokedFnMut {
     };
     
     template 
    -  requires requires(F f) {
    +  requires requires(F& f) {
         { std::invoke(f, std::declval()...) };
       }
     struct InvokedFnMut> {
    diff --git a/sus/fn/bind.h b/sus/fn/bind.h
    deleted file mode 100644
    index f1e01df70..000000000
    --- a/sus/fn/bind.h
    +++ /dev/null
    @@ -1,283 +0,0 @@
    -// Copyright 2022 Google LLC
    -//
    -// Licensed under the Apache License, Version 2.0 (the "License");
    -// you may not use this file except in compliance with the License.
    -// You may obtain a copy of the License at
    -//
    -//     https://www.apache.org/licenses/LICENSE-2.0
    -//
    -// Unless required by applicable law or agreed to in writing, software
    -// distributed under the License is distributed on an "AS IS" BASIS,
    -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    -// See the License for the specific language governing permissions and
    -// limitations under the License.
    -
    -// IWYU pragma: private, include "sus/fn/fn.h"
    -// IWYU pragma: friend "sus/.*"
    -#pragma once
    -
    -#include 
    -
    -#include "sus/fn/callable.h"
    -#include "sus/fn/fn_box_defn.h"
    -#include "sus/macros/__private/compiler_bugs.h"
    -#include "sus/macros/eval_macro.h"
    -#include "sus/macros/for_each.h"
    -#include "sus/macros/remove_parens.h"
    -#include "sus/marker/unsafe.h"
    -#include "sus/mem/forward.h"
    -#include "sus/mem/move.h"
    -
    -/// Bind a const lambda to storage for its bound arguments. The output can be
    -/// used to construct a FnOnceBox, FnMutBox, or FnBox.
    -///
    -/// The first argument is a list of variables that will be bound into storage
    -/// for access from the lambda, wrapped in sus_store(). If there are no
    -/// variables to mention, sus_store() can be empty, or use the sus_bind0() macro
    -/// which omits this list.
    -///
    -/// The second argument is a lambda, which can include captures. Any captures of
    -/// variables outside the lambda must be referenced in the sus_store() list.
    -///
    -/// Use `sus_take(x)` in the sus_store() list to move `x` into storage instead
    -/// of copying it.
    -///
    -/// Use `sus_unsafe_pointer(x)` to store a pointer named `x`. This is dangerous
    -/// and discouraged, and using smart pointers is strongly preferred.
    -///
    -/// # Example
    -///
    -/// This binds a lambda with 3 captures, the first two being variables from the
    -/// outside scope. The second variable is used as a reference to the storage,
    -/// rather that copying or moving it into the lambda.
    -/// ```
    -/// sus_bind(sus_store(a, b), [a, &b, c = 1]() {}))
    -/// ```
    -///
    -/// # Implementation note
    -/// The lambda may arrive in multiple arguments, if there is a comma in the
    -/// definition of it. Thus we use variadic arguments to capture all of the
    -/// lambda.
    -#define sus_bind(names, lambda, ...)                                        \
    -  [&]() {                                                                   \
    -    [&]() consteval {                                                       \
    -      sus_for_each(_sus__check_storage, sus_for_each_sep_none,              \
    -                   _sus__unpack names)                                      \
    -    }();                                                                    \
    -    using ::sus::fn::__private::SusBind;                                    \
    -    return SusBind(                                                         \
    -        [sus_for_each(_sus__declare_storage, sus_for_each_sep_comma,        \
    -                      _sus__unpack names)](Args&&... args) { \
    -          const auto x = lambda __VA_OPT__(, ) __VA_ARGS__;                 \
    -          const bool is_const =                                             \
    -              ::sus::fn::callable::CallableObjectConst;        \
    -          if constexpr (!is_const) {                                        \
    -            return ::sus::fn::__private::CheckCallableObjectConst<          \
    -                is_const>::template error();                          \
    -          } else {                                                          \
    -            return x(::sus::forward(args)...);                        \
    -          }                                                                 \
    -        });                                                                 \
    -  }()
    -
    -/// A variant of `sus_bind()` which only takes a lambda, omitting the
    -/// `sus_store()` list.  The output can be used to construct a FnOnceBox,
    -/// FnMutBox, or FnBox.
    -///
    -/// Because there is no `sus_store()` list, the lambda can not capture variables
    -/// from the outside scope, however it can still declare captures contained
    -/// entirely inside the lambda.
    -///
    -/// # Example
    -///
    -/// This defines a lambda with a capture `a` of type `int`, and binds it so it
    -/// can be used to construct a FnOnceBox, FnMutBox, or FnBox.
    -/// ```
    -/// sus_bind0([a = int(1)](char, int){})
    -/// ```
    -#define sus_bind0(lambda, ...) \
    -  sus_bind(sus_store(), lambda __VA_OPT__(, ) __VA_ARGS__)
    -
    -/// Bind a mutable lambda to storage for its bound arguments. The output can be
    -/// used to construct a FnOnceBox or FnMutBox.
    -///
    -/// Because the storage is mutable, the lambda may capture references to the
    -/// storage and mutate it, and the lambda itself may be marked mutable.
    -///
    -/// The first argument is a list of variables that will be bound into storage
    -/// for access from the lambda, wrapped in sus_store(). If there are no
    -/// variables to mention, sus_store() can be empty, or use the sus_bind0() macro
    -/// which omits this list.
    -///
    -/// The second argument is a lambda, which can include captures. Any captures of
    -/// variables outside the lambda must be referenced in the sus_store() list.
    -///
    -/// Use `sus_take(x)` in the sus_store() list to move `x` into storage instead
    -/// of copying it.
    -///
    -/// Use `sus_unsafe_pointer(x)` to store a pointer named `x`. This is dangerous
    -/// and discouraged, and using smart pointers is strongly preferred.
    -///
    -/// # Example
    -///
    -/// This binds a lambda with 3 captures, the first two being variables from the
    -/// outside scope. The second variable is used as a reference to the storage,
    -/// rather that copying or moving it into the lambda.
    -/// ```
    -/// sus_bind_mut(sus_store(a, b), [a, &b, c = 1]() {}))
    -/// ```
    -///
    -/// # Implementation note The lambda may arrive in multiple arguments, if there
    -/// is a comma in the definition of it. Thus we use variadic arguments to
    -/// capture all of the lambda.
    -#define sus_bind_mut(names, lambda, ...)                                 \
    -  [&]() {                                                                \
    -    [&]() consteval {                                                    \
    -      sus_for_each(_sus__check_storage, sus_for_each_sep_none,           \
    -                   _sus__unpack names)                                   \
    -    }();                                                                 \
    -    return ::sus::fn::__private::SusBind(                                \
    -        [sus_for_each(_sus__declare_storage_mut, sus_for_each_sep_comma, \
    -                      _sus__unpack names)](               \
    -            Args&&... args) mutable {                                    \
    -          auto x = lambda __VA_OPT__(, ) __VA_ARGS__;                    \
    -          return x(::sus::mem::forward(args)...);                  \
    -        });                                                              \
    -  }()
    -
    -/// A variant of `sus_bind_mut()` which only takes a lambda, omitting the
    -/// `sus_store()` list.  The output can be used to construct a FnOnceBox or
    -/// FnMutBox.
    -///
    -/// Because there is no `sus_store()` list, the lambda can not capture variables
    -/// from the outside scope, however it can still declare captures contained
    -/// entirely inside the lambda.
    -///
    -/// Can be used with a mutable lambda that can mutate its captures.
    -///
    -/// # Example
    -///
    -/// This defines a lambda with a capture `a` of type `int`, and binds it so it
    -/// can be used to construct a FnOnceBox, FnMutBox, or FnBox.
    -/// ```
    -/// sus_bind0_mut([a = int(1)](char, int){})
    -/// ```
    -#define sus_bind0_mut(lambda, ...) \
    -  sus_bind_mut(sus_store(), lambda __VA_OPT__(, ) __VA_ARGS__)
    -
    -/// Declares the set of captures from the outside scope in `sus_bind()` or
    -/// `sus_bind_mut()`.
    -#define sus_store(...) (__VA_ARGS__)
    -/// Marks a capture in the `sus_store()` list to be moved from the outside scope
    -/// instead of copied.
    -#define sus_take(x) (x, _sus__bind_move)
    -/// Marks a capture in the `sus_store()` list as a pointer which is being
    -/// intentionally and unsafely captured. Otherwise, pointers are not allowed to
    -/// be captured.
    -#define sus_unsafe_pointer(x) (x, _sus__bind_pointer)
    -
    -namespace sus::fn::__private {
    -
    -/// Helper type returned by sus_bind() and used to construct a closure.
    -template 
    -struct SusBind final {
    -  constexpr inline SusBind(F&& lambda) : lambda(::sus::move(lambda)) {}
    -
    -  /// The lambda generated by sus_bind() which holds the user-provided
    -  /// lambda and any storage required for it.
    -  F lambda;
    -};
    -
    -// The type generated by sus_unsafe_pointer() for storage in sus_bind().
    -template 
    -struct UnsafePointer;
    -
    -template 
    -struct UnsafePointer final {
    -  constexpr inline UnsafePointer(::sus::marker::UnsafeFnMarker, T* pointer)
    -      : pointer(pointer) {}
    -  T* pointer;
    -};
    -
    -template 
    -UnsafePointer(::sus::marker::UnsafeFnMarker, T*) -> UnsafePointer;
    -
    -template 
    -auto make_storage(T&& t) {
    -  return std::decay_t(forward(t));
    -}
    -template 
    -auto make_storage(T*) {
    -  static_assert(!std::is_pointer_v,
    -                "Can not store a pointer in sus_bind() except through "
    -                "sus_unsafe_pointer().");
    -}
    -template 
    -auto make_storage(UnsafePointer p) {
    -  return static_cast(p.pointer);
    -}
    -
    -template 
    -auto make_storage_mut(T&& t) {
    -  return std::decay_t(forward(t));
    -}
    -template 
    -auto make_storage_mut(T* t) {
    -  make_storage(t);
    -}
    -template 
    -auto make_storage_mut(UnsafePointer p) {
    -  return p.pointer;
    -}
    -
    -// Verifies the input is an lvalue (a name), so we can bind it to that same
    -// lvalue name in the resulting lambda.
    -template 
    -std::true_type is_lvalue(T&);
    -std::false_type is_lvalue(...);
    -
    -/// Helper used when verifying if a lambda is const. The template parameter
    -/// represents the constness of the lambda. When false, the error() function
    -/// generates a compiler error.
    -template 
    -struct CheckCallableObjectConst final {
    -  template 
    -  static constexpr inline auto error() {}
    -};
    -
    -template <>
    -struct CheckCallableObjectConst final {
    -  template 
    -  static consteval inline auto error() {
    -    throw "Use sus_bind_mut() to bind a mutable lambda";
    -  }
    -};
    -
    -}  // namespace sus::fn::__private
    -
    -// Private helper.
    -#define _sus__declare_storage(x)                                   \
    -  sus_eval_macro(_sus__declare_storage_impl, sus_remove_parens(x), \
    -                 _sus__bind_noop)
    -#define _sus__declare_storage_impl(x, modify, ...) \
    -  x = ::sus::fn::__private::make_storage(modify(x))
    -#define _sus__declare_storage_mut(x)                                   \
    -  sus_eval_macro(_sus__declare_storage_impl_mut, sus_remove_parens(x), \
    -                 _sus__bind_noop)
    -#define _sus__declare_storage_impl_mut(x, modify, ...) \
    -  x = ::sus::fn::__private::make_storage_mut(modify(x))
    -#define _sus__check_storage(x, ...)                              \
    -  sus_eval_macro(_sus__check_storage_impl, sus_remove_parens(x), \
    -                 _sus__bind_noop)
    -#define _sus__check_storage_impl(x, modify, ...)                     \
    -  static_assert(decltype(::sus::fn::__private::is_lvalue(x))::value, \
    -                "sus_bind() can only bind to variable names (lvalues).");
    -
    -#define _sus__bind_noop(x) x
    -#define _sus__bind_move(x) ::sus::move(x)
    -#define _sus__bind_pointer(x) \
    -  ::sus::fn::__private::UnsafePointer(::sus::marker::unsafe_fn, x)
    -
    -// Private helper.
    -#define _sus__unpack sus_bind_stored_argumnts_should_be_wrapped_in_sus_store
    -#define sus_bind_stored_argumnts_should_be_wrapped_in_sus_store(...) __VA_ARGS__
    diff --git a/sus/fn/callable.h b/sus/fn/callable.h
    deleted file mode 100644
    index 5e59a720e..000000000
    --- a/sus/fn/callable.h
    +++ /dev/null
    @@ -1,118 +0,0 @@
    -// Copyright 2022 Google LLC
    -//
    -// Licensed under the Apache License, Version 2.0 (the "License");
    -// you may not use this file except in compliance with the License.
    -// You may obtain a copy of the License at
    -//
    -//     https://www.apache.org/licenses/LICENSE-2.0
    -//
    -// Unless required by applicable law or agreed to in writing, software
    -// distributed under the License is distributed on an "AS IS" BASIS,
    -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    -// See the License for the specific language governing permissions and
    -// limitations under the License.
    -
    -// IWYU pragma: private, include "sus/fn/fn.h"
    -// IWYU pragma: friend "sus/.*"
    -#pragma once
    -
    -#include 
    -#include 
    -#include 
    -
    -#include "sus/mem/forward.h"
    -
    -namespace sus::fn::callable {
    -
    -template 
    -concept FunctionPointer = requires(T t) {
    -  { std::is_pointer_v };
    -};
    -
    -/// Verifies that T is a function pointer (or captureless lambda) that returns
    -/// a type convertible to `R` when called with `Args`.
    -///
    -/// This concept allows conversion of `Args` to the function's actual receiving
    -/// types and conversion from the function's return type to `R`.
    -///
    -// clang-format off
    -template 
    -concept FunctionPointerReturns = (
    -    FunctionPointer &&
    -    std::convertible_to, R> &&
    -    // We verify that `T` can be stored in a function pointer. Types must match
    -    // more strictly than just for invoking it.
    -    requires (R(*p)(Args...), T t) {
    -        { p = t };
    -    }
    -);
    -// clang-format on
    -
    -/// Verifies that T is a function pointer (or captureless lambda) that receives
    -/// exactly `Args` as its parameters without conversion, and returns `R` without
    -/// conversion.
    -///
    -/// This is concept is useful if you intend to store the pointer in a strongly
    -/// typed function pointer, as the types must match exactly. If you only intend
    -/// to call the function pointer, prefer `FunctionPointerReturns` which allows
    -/// appropriate conversions.
    -//
    -// clang-format off
    -template 
    -concept FunctionPointerMatches = (
    -    FunctionPointer &&
    -    // We verify that `T` can be stored in a function pointer. Types must match
    -    // more strictly than just for invoking it.
    -    requires (R(*p)(Args...), T t) {
    -        { p = t };
    -    }
    -);
    -// clang-format on
    -
    -// clang-format off
    -template 
    -concept FunctionPointerWith = (
    -    FunctionPointer &&
    -    requires (T t, Args&&... args) {
    -        std::invoke(t, ::sus::mem::forward(args)...);
    -    }
    -);
    -// clang-format on
    -
    -namespace __private {
    -
    -template 
    -inline constexpr bool callable_const(R (T::*)(Args...) const) {
    -  return true;
    -};
    -
    -}  // namespace __private
    -
    -template 
    -concept CallableObjectReturnsOnce =
    -    !FunctionPointer && requires(T t, Args&&... args) {
    -      {
    -        std::invoke(static_cast(t), ::sus::mem::forward(args)...)
    -      } -> std::convertible_to;
    -    };
    -
    -template 
    -concept CallableObjectReturnsConst =
    -    !FunctionPointer && requires(const T& t, Args&&... args) {
    -      {
    -        std::invoke(t, ::sus::mem::forward(args)...)
    -      } -> std::convertible_to;
    -    };
    -
    -template 
    -concept CallableObjectReturnsMut =
    -    !FunctionPointer && requires(T& t, Args&&... args) {
    -      {
    -        std::invoke(t, ::sus::mem::forward(args)...)
    -      } -> std::convertible_to;
    -    };
    -
    -template 
    -concept CallableObjectConst = __private::callable_const(&T::operator());
    -
    -}  // namespace sus::fn::callable
    diff --git a/sus/fn/fn.h b/sus/fn/fn.h
    index e1d31d206..36af7b383 100644
    --- a/sus/fn/fn.h
    +++ b/sus/fn/fn.h
    @@ -15,9 +15,6 @@
     #pragma once
     
     // IWYU pragma: begin_exports
    -#include "sus/fn/bind.h"
    -#include "sus/fn/fn_box_defn.h"
    -#include "sus/fn/fn_box_impl.h"
     #include "sus/fn/fn_concepts.h"
    -#include "sus/fn/fn_ref.h"
    +#include "sus/fn/fn_dyn.h"
     // IWYU pragma: end_exports
    diff --git a/sus/fn/fn_box_defn.h b/sus/fn/fn_box_defn.h
    deleted file mode 100644
    index d837d00ed..000000000
    --- a/sus/fn/fn_box_defn.h
    +++ /dev/null
    @@ -1,694 +0,0 @@
    -// Copyright 2022 Google LLC
    -//
    -// Licensed under the Apache License, Version 2.0 (the "License");
    -// you may not use this file except in compliance with the License.
    -// You may obtain a copy of the License at
    -//
    -//     https://www.apache.org/licenses/LICENSE-2.0
    -//
    -// Unless required by applicable law or agreed to in writing, software
    -// distributed under the License is distributed on an "AS IS" BASIS,
    -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    -// See the License for the specific language governing permissions and
    -// limitations under the License.
    -
    -// IWYU pragma: private, include "sus/fn/fn.h"
    -// IWYU pragma: friend "sus/.*"
    -#pragma once
    -
    -#include "sus/fn/callable.h"
    -#include "sus/lib/__private/forward_decl.h"
    -#include "sus/mem/forward.h"
    -#include "sus/mem/move.h"
    -#include "sus/mem/never_value.h"
    -#include "sus/mem/relocate.h"
    -
    -namespace sus::fn {
    -
    -namespace __private {
    -
    -/// The type-erased type (dropping the type of the internal lambda) of the
    -/// closure's heap-allocated storage.
    -struct FnBoxStorageBase;
    -
    -/// Helper type returned by sus_bind() and used to construct a closure.
    -template 
    -struct SusBind;
    -
    -/// Helper to determine which functions need to be instantiated for the closure,
    -/// to be called from FnOnceBox, FnMutBox, and/or FnBox.
    -///
    -/// This type indicates the closure can only be called from FnOnceBox.
    -enum StorageConstructionFnOnceBoxType { StorageConstructionFnOnceBox };
    -/// Helper to determine which functions need to be instantiated for the closure,
    -/// to be called from FnOnceBox, FnMutBox, and/or FnBox.
    -///
    -/// This type indicates the closure can be called from FnMutBox or FnOnceBox.
    -enum StorageConstructionFnMutBoxType { StorageConstructionFnMutBox };
    -/// Helper to determine which functions need to be instantiated for the closure,
    -/// to be called from FnOnceBox, FnMutBox, and/or FnBox.
    -///
    -/// This type indicates the closure can be called from FnBox, FnMutBox or
    -/// FnOnceBox.
    -enum StorageConstructionFnBoxType { StorageConstructionFnBox };
    -
    -/// Used to indicate if the closure is holding a function pointer or
    -/// heap-allocated storage.
    -enum FnBoxType {
    -  /// Holds a function pointer or captureless lambda.
    -  FnBoxPointer = 1,
    -  /// Holds the type-erased output of sus_bind() in a heap allocation.
    -  Storage = 2,
    -};
    -
    -}  // namespace __private
    -
    -// TODO: Consider generic lambdas, it should be possible to bind them into
    -// FnOnceBox/FnMutBox/FnBox?
    -// Example:
    -// ```
    -//    auto even = [](const auto& i) { return i % 2 == 0; };
    -//    auto r0 = sus::Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
    -//    10); auto result = r0.iter().filter(even);
    -// ```
    -
    -// TODO: There's no way to capture an rvalue right now. Need something like
    -// sus_take() but like sus_make(i, x.foo()) to bind `i = x.foo()`.
    -
    -// TODO: There's no way to capture a reference right now, sus_unsafe_ref()?
    -
    -/// A closure that erases the type of the internal callable object (lambda). A
    -/// FnOnceBox may only be called a single time.
    -///
    -/// FnBox can be used as a FnMutBox, which can be used as a FnOnceBox.
    -///
    -/// Lambdas without captures can be converted into a FnOnceBox, FnMutBox, or
    -/// FnBox directly. If the lambda has captured, it must be given to one of:
    -///
    -/// - `sus_bind(sus_store(..captures..), lambda)` to bind a const lambda which
    -/// captures variables from local state. Variables to be captured in the lambda
    -/// must also be named in sus_store(). `sus_bind()` only allows those named
    -/// variables to be captured, and ensures they are stored by value instead of by
    -/// reference.
    -///
    -/// - `sus_bind0(lambda)` to bind a const lambda which has bound variables that
    -/// don't capture state from outside the lambda, such as `[i = 2]() { return i;
    -/// }`.
    -///
    -/// - `sus_bind_mut(sus_store(...captures...), lambda)` to bind a mutable lambda
    -/// which captures variables from local state.
    -///
    -/// - `sus_bind0_mut(lambda)` to bind a mutable lambda which has bound variables
    -/// that don't capture state from outside the lambda, such as `[i = 2]() {
    -/// return ++i; }`.
    -///
    -/// Within sus_store(), a variable name can be wrapped with a helper to capture
    -/// in different ways:
    -///
    -/// - `sus_take(x)` will move `x` into the closure instead of copying it.
    -///
    -/// - `sus_unsafe_pointer(x)` will allow capturing a pointer. Otherwise it be
    -/// disallowed, and it is strongly discouraged as it requires careful present
    -/// and future understanding of the pointee's lifetime.
    -///
    -/// # Example
    -///
    -/// Moves `a` into the closure's storage, and copies b. The lambda then refers
    -/// to the closure's stored values by reference.
    -///
    -/// ```
    -/// int a = 1;
    -/// int b = 2;
    -/// FnOnceBox f = sus_bind_mut(
    -///   sus_store(sus_take(a), b), [&a, &b]() mutable { a += b; }
    -/// );
    -/// ```
    -///
    -/// Copies `a` into the closure's storage and defines a `b` from an rvalue.
    -/// Since `b` isn't referred to outside the FnBox it does not need to be bound.
    -///
    -/// ```
    -/// int a = 1;
    -/// FnOnceBox f = sus_bind_mut(
    -///   sus_store(a), [&a, b = 2]() mutable { a += b; }
    -/// );
    -/// ```
    -///
    -/// TODO: There's no way to do this currently, since it won't know what to name
    -/// the `x.foo()` value.
    -///
    -/// ```
    -/// struct { int foo() { return 2; } } x;
    -/// FnOnceBox f = sus_bind_mut(
    -///   sus_store(x.foo()), [&a]() mutable { a += 1; }
    -/// );
    -/// ```
    -///
    -/// # Why can a "const" FnBox convert to a mutable FnMutBox or FnOnceBox?
    -///
    -/// A FnMutBox or FnOnceBox is _allowed_ to mutate its storage, but a "const"
    -/// FnBox closure would just choose not to do so.
    -///
    -/// However, a `const FnBox` requires that the storage is not mutated, so it is
    -/// not useful if converted to a `const FnMutBox` or `const FnOnceBox` which are
    -/// only callable as mutable objects.
    -///
    -/// # Null pointers
    -///
    -/// A null function pointer is not allowed, constructing a FnOnceBox from a null
    -/// pointer will panic.
    -template 
    -class [[sus_trivial_abi]] FnOnceBox {
    - public:
    -  /// Construction from a function pointer or captureless lambda.
    -  ///
    -  /// #[doc.overloads=ctor.fnpointer]
    -  template <::sus::fn::callable::FunctionPointerMatches F>
    -  FnOnceBox(F ptr) noexcept;
    -
    -  /// Construction from a method or data member pointer.
    -  ///
    -  /// #[doc.overloads=ctor.methodpointer]
    -  template <::sus::fn::callable::CallableObjectReturnsOnce F>
    -    requires(std::is_member_function_pointer_v ||
    -             std::is_member_object_pointer_v)
    -  FnOnceBox(F ptr) noexcept
    -      : FnOnceBox(__private::StorageConstructionFnOnceBox, ptr) {}
    -
    -  /// Construction from a compatible FnOnceBox.
    -  ///
    -  /// #[doc.overloads=ctor.fnoncebox]
    -  template 
    -    requires(::sus::fn::callable::CallableObjectReturnsOnce<
    -             FnOnceBox &&, R, CallArgs...>)
    -  FnOnceBox(FnOnceBox&& box) noexcept
    -      : FnOnceBox(__private::StorageConstructionFnOnceBox,
    -                                  ::sus::move(box)) {}
    -
    -  /// Construction from a compatible FnMutBox.
    -  ///
    -  /// #[doc.overloads=ctor.fnmutbox]
    -  template 
    -    requires(::sus::fn::callable::CallableObjectReturnsOnce<
    -             FnMutBox, R, CallArgs...>)
    -  FnOnceBox(FnMutBox&& box) noexcept
    -      : FnOnceBox(__private::StorageConstructionFnOnceBox,
    -                                  ::sus::move(box)) {}
    -
    -  /// Construction from a compatible FnBox.
    -  ///
    -  /// #[doc.overloads=ctor.fnbox]
    -  template 
    -    requires(::sus::fn::callable::CallableObjectReturnsOnce,
    -                                                            R, CallArgs...>)
    -  FnOnceBox(FnBox&& box) noexcept
    -      : FnOnceBox(__private::StorageConstructionFnOnceBox,
    -                                  ::sus::move(box)) {}
    -
    -  /// Construction from the output of `sus_bind()`.
    -  ///
    -  /// #[doc.overloads=ctor.bind]
    -  template <::sus::fn::callable::CallableObjectReturnsOnce F>
    -  FnOnceBox(__private::SusBind&& holder) noexcept
    -      : FnOnceBox(__private::StorageConstructionFnOnceBox,
    -                  ::sus::move(holder.lambda)) {}
    -
    -  ~FnOnceBox() noexcept;
    -
    -  FnOnceBox(FnOnceBox&& o) noexcept;
    -  FnOnceBox& operator=(FnOnceBox&& o) noexcept;
    -
    -  FnOnceBox(const FnOnceBox&) noexcept = delete;
    -  FnOnceBox& operator=(const FnOnceBox&) noexcept = delete;
    -
    -  /// Runs and consumes the closure.
    -  inline R operator()(CallArgs... args) && noexcept;
    -
    -  /// `sus::construct::From` trait implementation.
    -  //
    -  // For function pointers or lambdas without captures.
    -  template <::sus::fn::callable::FunctionPointerMatches F>
    -  constexpr static auto from(F fn) noexcept {
    -    return FnOnceBox(fn);
    -  }
    -  // For method or data member pointers.
    -  template <::sus::fn::callable::CallableObjectReturnsOnce F>
    -    requires(std::is_member_function_pointer_v ||
    -             std::is_member_object_pointer_v)
    -  constexpr static auto from(F fn) noexcept {
    -    return FnOnceBox(fn);
    -  }
    -  // For compatible FnOnceBox.
    -  template 
    -    requires(::sus::fn::callable::CallableObjectReturnsOnce<
    -             FnOnceBox &&, R, CallArgs...>)
    -  constexpr static auto from(FnOnceBox&& box) noexcept {
    -    return FnOnceBox(::sus::move(box));
    -  }
    -  // For compatible FnMutBox.
    -  template 
    -    requires(::sus::fn::callable::CallableObjectReturnsOnce<
    -             FnMutBox, R, CallArgs...>)
    -  constexpr static auto from(FnMutBox&& box) noexcept {
    -    return FnOnceBox(::sus::move(box));
    -  }
    -  // For compatible FnBox.
    -  template 
    -    requires(::sus::fn::callable::CallableObjectReturnsOnce,
    -                                                            R, CallArgs...>)
    -  constexpr static auto from(FnBox&& box) noexcept {
    -    return FnOnceBox(::sus::move(box));
    -  }
    -  // For the output of `sus_bind()`.
    -  template <::sus::fn::callable::CallableObjectReturnsOnce F>
    -  constexpr static auto from(__private::SusBind&& holder) noexcept {
    -    return FnOnceBox(::sus::move(holder));
    -  }
    -
    - protected:
    -  template  F>
    -    requires(!(std::is_member_function_pointer_v> ||
    -               std::is_member_object_pointer_v>))
    -  FnOnceBox(ConstructionType, F&& lambda) noexcept;
    -
    -  template  F>
    -    requires(std::is_member_function_pointer_v ||
    -             std::is_member_object_pointer_v)
    -  FnOnceBox(ConstructionType, F ptr) noexcept;
    -
    -  union {
    -    // Used when the closure is a function pointer (or a captureless lambda,
    -    // which is converted to a function pointer).
    -    R (*fn_ptr_)(CallArgs...);
    -
    -    // Used when the closure is a lambda with storage, generated by
    -    // `sus_bind()`. This is a type-erased pointer to the heap storage.
    -    __private::FnBoxStorageBase* storage_;
    -  };
    -  // TODO: Could we query the allocator to see if the pointer here is heap
    -  // allocated or not, instead of storing a (pointer-sized, due to alignment)
    -  // flag here?
    -  __private::FnBoxType type_;
    -
    - private:
    -  // Functions to construct and return a pointer to a static vtable object for
    -  // the `__private::FnBoxStorage` being stored in `storage_`.
    -  //
    -  // A FnOnceBox needs to store only a single pointer, for call_once(). But a
    -  // FnBox needs to store three, for call(), call_mut() and call_once() since it
    -  // can be converted to a FnMutBox or FnOnceBox. For that reason we have 3
    -  // overloads where each one instantiates only the functions it requires - to
    -  // avoid trying to compile functions that aren't accessible and thus don't
    -  // need to be able to compile.
    -  template 
    -  static void make_vtable(FnBoxStorage&,
    -                          __private::StorageConstructionFnOnceBoxType) noexcept;
    -  template 
    -  static void make_vtable(FnBoxStorage&,
    -                          __private::StorageConstructionFnMutBoxType) noexcept;
    -  template 
    -  static void make_vtable(FnBoxStorage&,
    -                          __private::StorageConstructionFnBoxType) noexcept;
    -
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(fn_ptr_),
    -                                  decltype(storage_), decltype(type_));
    -  // Set the never value field to FnBoxPointer to perform a no-op destruction as
    -  // there is nothing cleaned up when holding a function pointer.
    -  sus_class_never_value_field(::sus::marker::unsafe_fn, FnOnceBox, type_,
    -                              static_cast<__private::FnBoxType>(0),
    -                              __private::FnBoxType::FnBoxPointer);
    -
    - protected:
    -  // For the NeverValueField.
    -  explicit FnOnceBox(::sus::mem::NeverValueConstructor) noexcept
    -      : type_(static_cast<__private::FnBoxType>(0)) {}
    -};
    -
    -/// A closure that erases the type of the internal callable object (lambda). A
    -/// FnMutBox may be called a multiple times, and may mutate its storage.
    -///
    -/// FnBox can be used as a FnMutBox, which can be used as a FnOnceBox.
    -///
    -/// Lambdas without captures can be converted into a FnOnceBox, FnMutBox, or
    -/// FnBox directly. If the lambda has captured, it must be given to one of:
    -///
    -/// - `sus_bind(sus_store(..captures..), lambda)` to bind a const lambda which
    -/// captures variables from local state. Variables to be captured in the
    -/// lambda must also be named in sus_store(). `sus_bind()` only allows those
    -/// named variables to be captured, and ensures they are stored by value
    -/// instead of by reference.
    -///
    -/// - `sus_bind0(lambda)` to bind a const lambda which has bound variables
    -/// that don't capture state from outside the lambda, such as `[i = 2]() {
    -/// return i;
    -/// }`.
    -///
    -/// - `sus_bind_mut(sus_store(...captures...), lambda)` to bind a mutable
    -/// lambda which captures variables from local state.
    -///
    -/// - `sus_bind0_mut(lambda)` to bind a mutable lambda which has bound
    -/// variables that don't capture state from outside the lambda, such as `[i =
    -/// 2]() { return ++i; }`.
    -///
    -/// Within sus_store(), a variable name can be wrapped with a helper to
    -/// capture in different ways:
    -///
    -/// - `sus_take(x)` will move `x` into the closure instead of copying it.
    -///
    -/// - `sus_unsafe_pointer(x)` will allow capturing a pointer. Otherwise it be
    -/// disallowed, and it is strongly discouraged as it requires careful present
    -/// and future understanding of the pointee's lifetime.
    -///
    -/// # Example
    -///
    -/// Moves `a` into the closure's storage, and copies b. The lambda then refers
    -/// to the closure's stored values by reference.
    -///
    -/// ```
    -/// int a = 1;
    -/// int b = 2;
    -/// FnMutBox f = sus_bind_mut(
    -///   sus_store(sus_take(a), b), [&a, &b]() mutable { a += b; }
    -/// );
    -/// ```
    -///
    -/// # Why can a "const" FnBox convert to a mutable FnMutBox or FnOnceBox?
    -///
    -/// A FnMutBox or FnOnceBox is _allowed_ to mutate its storage, but a "const"
    -/// FnBox closure would just choose not to do so.
    -///
    -/// However, a `const FnBox` requires that the storage is not mutated, so it
    -/// is not useful if converted to a `const FnMutBox` or `const FnOnceBox`
    -/// which are only callable as mutable objects.
    -///
    -/// # Null pointers
    -///
    -/// A null function pointer is not allowed, constructing a FnMutBox from a
    -/// null pointer will panic.
    -template 
    -class [[sus_trivial_abi]] FnMutBox
    -    : public FnOnceBox {
    - public:
    -  /// Construction from a function pointer or captureless lambda.
    -  ///
    -  /// #[doc.overloads=ctor.fnpointer]
    -  template <::sus::fn::callable::FunctionPointerMatches F>
    -  FnMutBox(F ptr) noexcept : FnOnceBox(::sus::move(ptr)) {}
    -
    -  /// Construction from a method or data member pointer.
    -  ///
    -  /// #[doc.overloads=ctor.methodpointer]
    -  template <::sus::fn::callable::CallableObjectReturnsMut F>
    -    requires(std::is_member_function_pointer_v ||
    -             std::is_member_object_pointer_v)
    -  FnMutBox(F ptr) noexcept
    -      : FnOnceBox(__private::StorageConstructionFnMutBox, ptr) {
    -  }
    -
    -  /// Construction from a compatible FnMutBox.
    -  ///
    -  /// #[doc.overloads=ctor.fnmutbox]
    -  template 
    -    requires(::sus::fn::callable::CallableObjectReturnsMut<
    -             FnMutBox, R, CallArgs...>)
    -  FnMutBox(FnMutBox&& box) noexcept
    -      : FnOnceBox(__private::StorageConstructionFnMutBox,
    -                                  ::sus::move(box)) {}
    -
    -  /// Construction from a compatible FnBox.
    -  ///
    -  /// #[doc.overloads=ctor.fnbox]
    -  template 
    -    requires(::sus::fn::callable::CallableObjectReturnsMut,
    -                                                           R, CallArgs...>)
    -  FnMutBox(FnBox&& box) noexcept
    -      : FnOnceBox(__private::StorageConstructionFnMutBox,
    -                                  ::sus::move(box)) {}
    -
    -  /// Construction from the output of `sus_bind()`.
    -  ///
    -  /// #[doc.overloads=ctor.bind]
    -  template <::sus::fn::callable::CallableObjectReturnsMut F>
    -  FnMutBox(__private::SusBind&& holder) noexcept
    -      : FnOnceBox(__private::StorageConstructionFnMutBox,
    -                                  ::sus::move(holder.lambda)) {}
    -
    -  ~FnMutBox() noexcept = default;
    -
    -  FnMutBox(FnMutBox&&) noexcept = default;
    -  FnMutBox& operator=(FnMutBox&&) noexcept = default;
    -
    -  FnMutBox(const FnMutBox&) noexcept = delete;
    -  FnMutBox& operator=(const FnMutBox&) noexcept = delete;
    -
    -  /// Runs the closure.
    -  inline R operator()(CallArgs... args) & noexcept;
    -  inline R operator()(CallArgs... args) && noexcept {
    -    return static_cast&&>(*this)(
    -        forward(args)...);
    -  }
    -
    -  /// `sus::construct::From` trait implementation for function pointers or
    -  /// lambdas without captures.
    -  ///
    -  /// #[doc.overloads=from.fnpointer]
    -  template <::sus::fn::callable::FunctionPointerMatches F>
    -  constexpr static auto from(F fn) noexcept {
    -    return FnMutBox(fn);
    -  }
    -
    -  /// `sus::construct::From` trait implementation for method or data member
    -  /// pointers.
    -  ///
    -  /// #[doc.overloads=from.method]
    -  template <::sus::fn::callable::CallableObjectReturnsMut F>
    -    requires(std::is_member_function_pointer_v ||
    -             std::is_member_object_pointer_v)
    -  constexpr static auto from(F fn) noexcept {
    -    return FnMutBox(fn);
    -  }
    -
    -  /// `sus::construct::From` compatible FnMutBox.
    -  ///
    -  /// #[doc.overloads=from.fnmutbox]
    -  template 
    -    requires(::sus::fn::callable::CallableObjectReturnsMut<
    -             FnMutBox, R, CallArgs...>)
    -  constexpr static auto from(FnMutBox&& box) noexcept {
    -    return FnMutBox(::sus::move(box));
    -  }
    -
    -  /// `sus::construct::From` compatible FnBox.
    -  ///
    -  /// #[doc.overloads=from.fnbox]
    -  template 
    -    requires(::sus::fn::callable::CallableObjectReturnsMut,
    -                                                           R, CallArgs...>)
    -  constexpr static auto from(FnBox&& box) noexcept {
    -    return FnMutBox(::sus::move(box));
    -  }
    -
    -  /// `sus::construct::From` trait implementation for the output of
    -  /// `sus_bind()`.
    -  ///
    -  /// #[doc.overloads=from.callableobject]
    -  template <::sus::fn::callable::CallableObjectReturnsMut F>
    -  constexpr static auto from(__private::SusBind&& holder) noexcept {
    -    return FnMutBox(::sus::move(holder));
    -  }
    -
    - protected:
    -  // This class may only have trivially-destructible storage and must not
    -  // do anything in its destructor, as `FnOnceBox` moves from itself, and it
    -  // would slice that off.
    -
    -  template  F>
    -  FnMutBox(ConstructionType c, F&& lambda) noexcept
    -      : FnOnceBox(c, ::sus::move(lambda)) {}
    -
    - private:
    -  sus_class_trivially_relocatable_unchecked(::sus::marker::unsafe_fn);
    -  // Copied from FnOnceBox base class.
    -  sus_class_never_value_field(::sus::marker::unsafe_fn, FnMutBox,
    -                              FnOnceBox::type_,
    -                              static_cast<__private::FnBoxType>(0),
    -                              __private::FnBoxType::FnBoxPointer);
    -
    - protected:
    -  explicit FnMutBox(::sus::mem::NeverValueConstructor c) noexcept
    -      : FnOnceBox(c) {}
    -};
    -
    -/// A closure that erases the type of the internal callable object (lambda). A
    -/// FnBox may be called a multiple times, and will not mutate its storage.
    -///
    -/// FnBox can be used as a FnMutBox, which can be used as a FnOnceBox.
    -///
    -/// Lambdas without captures can be converted into a FnOnceBox, FnMutBox, or
    -/// FnBox directly. If the lambda has captured, it must be given to one of:
    -///
    -/// - `sus_bind(sus_store(..captures..), lambda)` to bind a const lambda which
    -/// captures variables from local state. Variables to be captured in the
    -/// lambda must also be named in sus_store(). `sus_bind()` only allows those
    -/// named variables to be captured, and ensures they are stored by value
    -/// instead of by reference.
    -///
    -/// - `sus_bind0(lambda)` to bind a const lambda which has bound variables
    -/// that don't capture state from outside the lambda, such as `[i = 2]() {
    -/// return i;
    -/// }`.
    -///
    -/// - `sus_bind_mut(sus_store(...captures...), lambda)` to bind a mutable
    -/// lambda which captures variables from local state.
    -///
    -/// - `sus_bind0_mut(lambda)` to bind a mutable lambda which has bound
    -/// variables that don't capture state from outside the lambda, such as `[i =
    -/// 2]() { return ++i; }`.
    -///
    -/// Within sus_store(), a variable name can be wrapped with a helper to
    -/// capture in different ways:
    -///
    -/// - `sus_take(x)` will move `x` into the closure instead of copying it.
    -///
    -/// - `sus_unsafe_pointer(x)` will allow capturing a pointer. Otherwise it be
    -/// disallowed, and it is strongly discouraged as it requires careful present
    -/// and future understanding of the pointee's lifetime.
    -///
    -/// # Example
    -///
    -/// Moves `a` into the closure's storage, and copies b. The lambda then refers
    -/// to the closure's stored values by reference.
    -///
    -/// ```
    -/// int a = 1;
    -/// int b = 2;
    -/// FnBox f = sus_bind(
    -///   sus_store(sus_take(a), b), [&a, &b]() { return a + b; }
    -/// );
    -/// ```
    -///
    -/// # Why can a "const" FnBox convert to a mutable FnMutBox or FnOnceBox?
    -///
    -/// A FnMutBox or FnOnceBox is _allowed_ to mutate its storage, but a "const"
    -/// FnBox closure would just choose not to do so.
    -///
    -/// However, a `const FnBox` requires that the storage is not mutated, so it
    -/// is not useful if converted to a `const FnMutBox` or `const FnOnceBox`
    -/// which are only callable as mutable objects.
    -///
    -/// # Null pointers
    -///
    -/// A null function pointer is not allowed, constructing a FnBox from a null
    -/// pointer will panic.
    -template 
    -class [[sus_trivial_abi]] FnBox final
    -    : public FnMutBox {
    - public:
    -  /// Construction from a function pointer or captureless lambda.
    -  ///
    -  /// #[doc.overloads=ctor.fnpointer]
    -  template <::sus::fn::callable::FunctionPointerMatches F>
    -  FnBox(F ptr) noexcept : FnMutBox(ptr) {}
    -
    -  /// Construction from a method or data member pointer.
    -  ///
    -  /// #[doc.overloads=ctor.methodpointer]
    -  template <::sus::fn::callable::CallableObjectReturnsConst F>
    -    requires(std::is_member_function_pointer_v ||
    -             std::is_member_object_pointer_v)
    -  FnBox(F ptr) noexcept
    -      : FnMutBox(__private::StorageConstructionFnBox, ptr) {}
    -
    -  /// Construction from a compatible FnBox.
    -  ///
    -  /// #[doc.overloads=ctor.fnbox]
    -  template 
    -    requires(::sus::fn::callable::CallableObjectReturnsConst,
    -                                                             R, CallArgs...>)
    -  FnBox(FnBox&& box) noexcept
    -      : FnMutBox(__private::StorageConstructionFnBox,
    -                                 ::sus::move(box)) {}
    -
    -  /// Construction from the output of `sus_bind()`.
    -  ///
    -  /// #[doc.overloads=ctor.bind]
    -  template <::sus::fn::callable::CallableObjectReturnsConst F>
    -  FnBox(__private::SusBind&& holder) noexcept
    -      : FnMutBox(__private::StorageConstructionFnBox,
    -                                 ::sus::move(holder.lambda)) {}
    -
    -  ~FnBox() noexcept = default;
    -
    -  FnBox(FnBox&&) noexcept = default;
    -  FnBox& operator=(FnBox&&) noexcept = default;
    -
    -  FnBox(const FnBox&) noexcept = delete;
    -  FnBox& operator=(const FnBox&) noexcept = delete;
    -
    -  /// Runs the closure.
    -  inline R operator()(CallArgs... args) const& noexcept;
    -  inline R operator()(CallArgs... args) && noexcept {
    -    return static_cast&&>(*this)(
    -        forward(args)...);
    -  }
    -
    -  /// `sus::construct::From` trait implementation for function pointers or
    -  /// lambdas without captures.
    -  ///
    -  /// #[doc.overloads=from.fnpointer]
    -  template <::sus::fn::callable::FunctionPointerMatches F>
    -  constexpr static auto from(F fn) noexcept {
    -    return FnBox(fn);
    -  }
    -
    -  /// `sus::construct::From` trait implementation for method or data member
    -  /// pointers.
    -  ///
    -  /// #[doc.overloads=from.method]
    -  template <::sus::fn::callable::CallableObjectReturnsConst F>
    -    requires(std::is_member_function_pointer_v ||
    -             std::is_member_object_pointer_v)
    -  constexpr static auto from(F fn) noexcept {
    -    return FnBox(fn);
    -  }
    -
    -  /// `sus::construct::From` compatible FnBox.
    -  ///
    -  /// #[doc.overloads=from.fnbox]
    -  template 
    -    requires(::sus::fn::callable::CallableObjectReturnsConst,
    -                                                             R, CallArgs...>)
    -  constexpr static auto from(FnBox&& box) noexcept {
    -    return FnMutBox(::sus::move(box));
    -  }
    -
    -  /// `sus::construct::From` trait implementation for the output of
    -  /// `sus_bind()`.
    -  /// #[doc.overloads=1]
    -  template <::sus::fn::callable::CallableObjectReturnsConst F>
    -  constexpr static auto from(__private::SusBind&& holder) noexcept {
    -    return FnBox(::sus::move(holder));
    -  }
    -
    - private:
    -  // This class may only have trivially-destructible storage and must not
    -  // do anything in its destructor, as `FnOnceBox` moves from itself, and it
    -  // would slice that off.
    -
    -  template <::sus::fn::callable::CallableObjectReturnsConst F>
    -  FnBox(__private::StorageConstructionFnBoxType, F&& fn) noexcept;
    -
    -  sus_class_trivially_relocatable_unchecked(::sus::marker::unsafe_fn);
    -  // Copied from FnOnceBox base class.
    -  sus_class_never_value_field(::sus::marker::unsafe_fn, FnBox,
    -                              FnOnceBox::type_,
    -                              static_cast<__private::FnBoxType>(0),
    -                              __private::FnBoxType::FnBoxPointer);
    -  explicit FnBox(::sus::mem::NeverValueConstructor c) noexcept
    -      : FnMutBox(c) {}
    -};
    -
    -}  // namespace sus::fn
    diff --git a/sus/fn/fn_box_impl.h b/sus/fn/fn_box_impl.h
    deleted file mode 100644
    index 72453d650..000000000
    --- a/sus/fn/fn_box_impl.h
    +++ /dev/null
    @@ -1,225 +0,0 @@
    -// Copyright 2022 Google LLC
    -//
    -// Licensed under the Apache License, Version 2.0 (the "License");
    -// you may not use this file except in compliance with the License.
    -// You may obtain a copy of the License at
    -//
    -//     https://www.apache.org/licenses/LICENSE-2.0
    -//
    -// Unless required by applicable law or agreed to in writing, software
    -// distributed under the License is distributed on an "AS IS" BASIS,
    -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    -// See the License for the specific language governing permissions and
    -// limitations under the License.
    -
    -// IWYU pragma: private, include "sus/fn/fn.h"
    -// IWYU pragma: friend "sus/.*"
    -#pragma once
    -
    -#include "sus/assertions/check.h"
    -#include "sus/assertions/unreachable.h"
    -#include "sus/fn/__private/fn_box_storage.h"
    -#include "sus/fn/fn_box_defn.h"
    -#include "sus/macros/__private/compiler_bugs.h"
    -#include "sus/mem/replace.h"
    -
    -namespace sus::fn {
    -
    -template 
    -template <::sus::fn::callable::FunctionPointerMatches F>
    -FnOnceBox::FnOnceBox(F ptr) noexcept
    -    : fn_ptr_(ptr), type_(__private::FnBoxPointer) {
    -  ::sus::check(ptr != nullptr);
    -}
    -
    -template 
    -template  F>
    -  requires(!(std::is_member_function_pointer_v> ||
    -             std::is_member_object_pointer_v>))
    -FnOnceBox::FnOnceBox(ConstructionType construction,
    -                                     F&& lambda) noexcept
    -    : type_(__private::Storage) {
    -  // TODO: Allow overriding the global allocator? Use the allocator in place of
    -  // `new` and `delete` directly?
    -  auto* s = new __private::FnBoxStorage(::sus::move(lambda));
    -  make_vtable(*s, construction);
    -  storage_ = s;
    -}
    -
    -template 
    -template  F>
    -  requires(std::is_member_function_pointer_v ||
    -           std::is_member_object_pointer_v)
    -FnOnceBox::FnOnceBox(ConstructionType construction,
    -                                     F ptr) noexcept
    -    : type_(__private::Storage) {
    -  ::sus::check(ptr != nullptr);
    -  // TODO: Allow overriding the global allocator? Use the allocator in place of
    -  // `new` and `delete` directly?
    -  auto* s = new __private::FnBoxStorage(ptr);
    -  make_vtable(*s, construction);
    -  storage_ = s;
    -}
    -
    -template 
    -template 
    -void FnOnceBox::make_vtable(
    -    FnBoxStorage& storage,
    -    __private::StorageConstructionFnOnceBoxType) noexcept {
    -  static __private::FnBoxStorageVtable vtable = {
    -      .call_once = &FnBoxStorage::template call_once,
    -      .call_mut = nullptr,
    -      .call = nullptr,
    -  };
    -  storage.vtable.insert(vtable);
    -}
    -
    -template 
    -template 
    -void FnOnceBox::make_vtable(
    -    FnBoxStorage& storage,
    -    __private::StorageConstructionFnMutBoxType) noexcept {
    -  static __private::FnBoxStorageVtable vtable = {
    -      .call_once = &FnBoxStorage::template call_once,
    -      .call_mut = &FnBoxStorage::template call_mut,
    -      .call = nullptr,
    -  };
    -  storage.vtable.insert(vtable);
    -}
    -
    -template 
    -template 
    -void FnOnceBox::make_vtable(
    -    FnBoxStorage& storage, __private::StorageConstructionFnBoxType) noexcept {
    -  static __private::FnBoxStorageVtable vtable = {
    -      .call_once = &FnBoxStorage::template call_once,
    -      .call_mut = &FnBoxStorage::template call_mut,
    -      .call = &FnBoxStorage::template call,
    -  };
    -  storage.vtable.insert(vtable);
    -}
    -
    -template 
    -FnOnceBox::~FnOnceBox() noexcept {
    -  switch (type_) {
    -    case __private::FnBoxPointer: break;
    -    case __private::Storage: {
    -      if (auto* s = ::sus::mem::replace(storage_, nullptr); s) delete s;
    -      break;
    -    }
    -  }
    -  // The NeverValue in `type_` means we get here and do nothing.
    -}
    -
    -template 
    -FnOnceBox::FnOnceBox(FnOnceBox&& o) noexcept : type_(o.type_) {
    -  switch (type_) {
    -    case __private::FnBoxPointer:
    -      ::sus::check(o.fn_ptr_);  // Catch use-after-move.
    -      fn_ptr_ = ::sus::mem::replace(o.fn_ptr_, nullptr);
    -      break;
    -    case __private::Storage:
    -      ::sus::check(o.storage_);  // Catch use-after-move.
    -      storage_ = ::sus::mem::replace(o.storage_, nullptr);
    -      break;
    -  }
    -}
    -
    -template 
    -FnOnceBox& FnOnceBox::operator=(
    -    FnOnceBox&& o) noexcept {
    -  switch (type_) {
    -    case __private::FnBoxPointer: break;
    -    case __private::Storage:
    -      if (auto* s = ::sus::mem::replace(storage_, nullptr); s) delete s;
    -  }
    -  switch (type_ = o.type_) {
    -    case __private::FnBoxPointer:
    -      ::sus::check(o.fn_ptr_);  // Catch use-after-move.
    -      fn_ptr_ = ::sus::mem::replace(o.fn_ptr_, nullptr);
    -      break;
    -    case __private::Storage:
    -      ::sus::check(o.storage_);  // Catch use-after-move.
    -      storage_ = ::sus::mem::replace(o.storage_, nullptr);
    -      break;
    -  }
    -  return *this;
    -}
    -
    -template 
    -R FnOnceBox::operator()(CallArgs... args) && noexcept {
    -  switch (type_) {
    -    case __private::FnBoxPointer: {
    -      ::sus::check(fn_ptr_);  // Catch use-after-move.
    -      auto* fn = ::sus::mem::replace(fn_ptr_, nullptr);
    -      return std::invoke(fn, static_cast(args)...);
    -    }
    -    case __private::Storage: {
    -      ::sus::check(storage_);  // Catch use-after-move.
    -      auto* storage = ::sus::mem::replace(storage_, nullptr);
    -      auto& vtable =
    -          static_cast&>(
    -              storage->vtable.as_mut().unwrap());
    -
    -      // Delete storage, after the call_once() is complete.
    -      //
    -      // TODO: `storage` and `storage_` should be owning smart pointers.
    -      struct DeleteStorage final {
    -        sus_clang_bug_54040(
    -            constexpr inline DeleteStorage(__private::FnBoxStorageBase* storage)
    -            : storage(storage){});
    -        ~DeleteStorage() { delete storage; }
    -        __private::FnBoxStorageBase* storage;
    -      } deleter(storage);
    -
    -      return vtable.call_once(
    -          static_cast<__private::FnBoxStorageBase&&>(*storage),
    -          forward(args)...);
    -    }
    -  }
    -  ::sus::unreachable_unchecked(::sus::marker::unsafe_fn);
    -}
    -
    -template 
    -R FnMutBox::operator()(CallArgs... args) & noexcept {
    -  using Super = FnOnceBox;
    -  switch (Super::type_) {
    -    case __private::FnBoxPointer:
    -      ::sus::check(Super::fn_ptr_);  // Catch use-after-move.
    -      return Super::fn_ptr_(static_cast(args)...);
    -    case __private::Storage: {
    -      ::sus::check(Super::storage_);  // Catch use-after-move.
    -      auto& vtable =
    -          static_cast&>(
    -              Super::storage_->vtable.as_mut().unwrap());
    -      return vtable.call_mut(
    -          static_cast<__private::FnBoxStorageBase&>(*Super::storage_),
    -          ::sus::forward(args)...);
    -    }
    -  }
    -  ::sus::unreachable_unchecked(::sus::marker::unsafe_fn);
    -}
    -
    -template 
    -R FnBox::operator()(CallArgs... args) const& noexcept {
    -  using Super = FnOnceBox;
    -  switch (Super::type_) {
    -    case __private::FnBoxPointer:
    -      ::sus::check(Super::fn_ptr_);  // Catch use-after-move.
    -      return Super::fn_ptr_(static_cast(args)...);
    -    case __private::Storage: {
    -      ::sus::check(Super::storage_);  // Catch use-after-move.
    -      auto& vtable =
    -          static_cast&>(
    -              Super::storage_->vtable.as_mut().unwrap());
    -      return vtable.call(
    -          static_cast(*Super::storage_),
    -          ::sus::forward(args)...);
    -    }
    -  }
    -  ::sus::unreachable_unchecked(::sus::marker::unsafe_fn);
    -}
    -
    -}  // namespace sus::fn
    diff --git a/sus/fn/fn_box_unittest.cc b/sus/fn/fn_box_unittest.cc
    deleted file mode 100644
    index a07f75c94..000000000
    --- a/sus/fn/fn_box_unittest.cc
    +++ /dev/null
    @@ -1,709 +0,0 @@
    -// Copyright 2022 Google LLC
    -//
    -// Licensed under the Apache License, Version 2.0 (the "License");
    -// you may not use this file except in compliance with the License.
    -// You may obtain a copy of the License at
    -//
    -//     https://www.apache.org/licenses/LICENSE-2.0
    -//
    -// Unless required by applicable law or agreed to in writing, software
    -// distributed under the License is distributed on an "AS IS" BASIS,
    -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    -// See the License for the specific language governing permissions and
    -// limitations under the License.
    -
    -#include 
    -
    -#include "googletest/include/gtest/gtest.h"
    -#include "sus/construct/into.h"
    -#include "sus/fn/fn.h"
    -#include "sus/iter/iterator.h"
    -#include "sus/mem/forward.h"
    -#include "sus/mem/move.h"
    -#include "sus/mem/replace.h"
    -#include "sus/option/option.h"
    -#include "sus/prelude.h"
    -
    -namespace {
    -
    -using sus::construct::Into;
    -using sus::fn::FnBox;
    -using sus::fn::FnMutBox;
    -using sus::fn::FnOnceBox;
    -
    -struct Copyable {
    -  Copyable(int i) : i(i) {}
    -  Copyable(const Copyable& c) = default;
    -  Copyable& operator=(const Copyable& c) = default;
    -  ~Copyable() { i = -10000000; }
    -
    -  int i = 0;
    -};
    -
    -struct MoveOnly {
    -  MoveOnly(int i) : i(i) {}
    -  MoveOnly(const MoveOnly& c) = delete;
    -  MoveOnly& operator=(const MoveOnly& c) = delete;
    -  MoveOnly(MoveOnly&& c) : i(::sus::mem::replace(c.i, -1)) {}
    -  MoveOnly& operator=(MoveOnly&& c) {
    -    i = ::sus::mem::replace(c.i, -1);
    -    return *this;
    -  }
    -  ~MoveOnly() { i = -10000000; }
    -
    -  int i = 0;
    -};
    -
    -// clang-format-off
    -
    -struct BaseClass {};
    -struct SubClass : public BaseClass {};
    -
    -static_assert(sizeof(FnOnceBox) > sizeof(void (*)()));
    -static_assert(sizeof(FnOnceBox) <= sizeof(void (*)()) * 2);
    -
    -void v_v_function() {}
    -int i_f_function(float) { return 0; }
    -void v_f_function(float) {}
    -BaseClass* b_b_function(BaseClass* b) { return b; }
    -SubClass* s_b_function(BaseClass* b) { return static_cast(b); }
    -SubClass* s_s_function(SubClass* b) { return b; }
    -
    -// These emulate binding with sus_bind(), but don't use it cuz capturing lambdas
    -// in a constant expression won't work.
    -auto b_b_lambda = sus::fn::__private::SusBind(
    -    [a = 1](BaseClass* b) -> BaseClass* { return b; });
    -auto s_b_lambda = sus::fn::__private::SusBind(
    -    [a = 1](BaseClass* b) -> SubClass* { return static_cast(b); });
    -auto s_s_lambda = sus::fn::__private::SusBind(
    -    [a = 1](SubClass* b) -> SubClass* { return b; });
    -
    -// FnBox types all have a never-value field.
    -static_assert(sus::mem::NeverValueField>);
    -static_assert(sus::mem::NeverValueField>);
    -static_assert(sus::mem::NeverValueField>);
    -// Which allows them to not require a flag in Option.
    -static_assert(sizeof(sus::Option>) ==
    -              sizeof(FnOnceBox));
    -
    -// Closures can not be copied, as their storage is uniquely owned.
    -static_assert(!std::is_copy_constructible_v>);
    -static_assert(!std::is_copy_assignable_v>);
    -static_assert(!std::is_copy_constructible_v>);
    -static_assert(!std::is_copy_assignable_v>);
    -static_assert(!std::is_copy_constructible_v>);
    -static_assert(!std::is_copy_assignable_v>);
    -// Closures can be moved.
    -static_assert(std::is_move_constructible_v>);
    -static_assert(std::is_move_assignable_v>);
    -static_assert(std::is_move_constructible_v>);
    -static_assert(std::is_move_assignable_v>);
    -static_assert(std::is_move_constructible_v>);
    -static_assert(std::is_move_assignable_v>);
    -
    -// Closures are trivially relocatable.
    -static_assert(sus::mem::relocate_by_memcpy>);
    -static_assert(sus::mem::relocate_by_memcpy>);
    -static_assert(sus::mem::relocate_by_memcpy>);
    -
    -// A function pointer, or convertible lambda, can be bound to FnOnceBox,
    -// FnMutBox and FnBox.
    -static_assert(std::is_constructible_v, decltype([]() {})>);
    -static_assert(std::is_constructible_v, decltype([]() {})>);
    -static_assert(std::is_constructible_v, decltype([]() {})>);
    -static_assert(
    -    std::is_constructible_v, decltype(v_v_function)>);
    -static_assert(
    -    std::is_constructible_v, decltype(v_v_function)>);
    -static_assert(std::is_constructible_v, decltype(v_v_function)>);
    -// Non-void types for the same.
    -static_assert(std::is_constructible_v,
    -                                      decltype([](float) { return 1; })>);
    -static_assert(std::is_constructible_v,
    -                                      decltype([](float) { return 1; })>);
    -static_assert(std::is_constructible_v,
    -                                      decltype([](float) { return 1; })>);
    -static_assert(
    -    std::is_constructible_v, decltype(i_f_function)>);
    -static_assert(
    -    std::is_constructible_v, decltype(i_f_function)>);
    -static_assert(
    -    std::is_constructible_v, decltype(i_f_function)>);
    -
    -// Lambdas with bound args can't be passed without sus_bind().
    -static_assert(!std::is_constructible_v,
    -                                       decltype([i = int(1)]() { (void)i; })>);
    -static_assert(!std::is_constructible_v<
    -              FnOnceBox, decltype([i = int(1)]() mutable { ++i; })>);
    -
    -// The return type of the FnBox must match that of the lambda. It will not allow
    -// converting to void.
    -static_assert(std::is_constructible_v,
    -                                      decltype(s_b_function)>);
    -static_assert(
    -    !std::is_constructible_v, decltype(b_b_function)>);
    -static_assert(!std::is_constructible_v,
    -                                       decltype(b_b_function)>);
    -static_assert(std::is_constructible_v,
    -                                      decltype(s_b_lambda)>);
    -static_assert(
    -    !std::is_constructible_v, decltype(b_b_lambda)>);
    -static_assert(!std::is_constructible_v,
    -                                       decltype(b_b_lambda)>);
    -// Similarly, argument types can't be converted to a different type.
    -static_assert(std::is_constructible_v,
    -                                      decltype(s_s_function)>);
    -static_assert(!std::is_constructible_v,
    -                                       decltype(s_s_function)>);
    -static_assert(
    -    std::is_constructible_v, decltype(s_s_lambda)>);
    -static_assert(!std::is_constructible_v,
    -                                       decltype(s_s_lambda)>);
    -// But FnBox type is compatible with convertible return and argument types in
    -// opposite directions.
    -// - If the return type Y of a lambda is convertible _to_ X, then FnBox can
    -// be
    -//   used to store it.
    -// - If the argument type Y of a lambda is convertible _from_ X, then FnBox<(X)>
    -//   can be used to store it.
    -//
    -// In both cases, the FnBox is more strict than the lambda, guaranteeing that
    -// the lambda's requirements are met.
    -static_assert(std::is_constructible_v,
    -                                      decltype(s_b_lambda)>);
    -static_assert(
    -    std::is_constructible_v, decltype(s_b_lambda)>);
    -// HOWEVER: When FnBox is passed a function pointer, it stores a function
    -// pointer. C++20 does not yet allow us to erase the type of that function
    -// pointer in a constexpr context. So the types in the pointer must match
    -// exactly to the FnBox's signature.
    -static_assert(!std::is_constructible_v,
    -                                       decltype(s_b_function)>);
    -static_assert(!std::is_constructible_v,
    -                                       decltype(s_b_function)>);
    -
    -// Lambdas with bound args can be passed with sus_bind(). Can use sus_bind0()
    -// when there's no captured variables.
    -static_assert(std::is_constructible_v, decltype([]() {
    -                                        return sus_bind0([i = int(1)]() {});
    -                                      }())>);
    -// And use sus_bind0_mut for a mutable lambda.
    -static_assert(std::is_constructible_v, decltype([]() {
    -                                        return sus_bind0_mut(
    -                                            [i = int(1)]() mutable { ++i; });
    -                                      }())>);
    -
    -// FnBox that are compatible can be converted to.
    -static_assert(std::is_constructible_v,
    -                                      FnBox>);
    -static_assert(!std::is_constructible_v,
    -                                       FnBox>);
    -static_assert(std::is_constructible_v,
    -                                      FnMutBox>);
    -static_assert(!std::is_constructible_v,
    -                                       FnMutBox>);
    -static_assert(std::is_constructible_v,
    -                                      FnOnceBox>);
    -static_assert(!std::is_constructible_v,
    -                                       FnOnceBox>);
    -
    -static_assert(std::is_constructible_v,
    -                                      FnMutBox>);
    -static_assert(std::is_constructible_v,
    -                                      FnBox>);
    -static_assert(std::is_constructible_v,
    -                                      FnBox>);
    -
    -// This incorrectly uses sus_bind0 with a mutable lambda, which produces a
    -// warning while also being non-constructible. But we build with errors enabled
    -// so it fails to compile instead of just failing the assert.
    -//
    -// TODO: It doesn't seem possible to disable this error selectively here, as the
    -// actual call happens in a template elsewhere. So that prevents us from
    -// checking the non-constructibility if the warning isn't compiled as an error.
    -//
    -// It would be nice to be able to produce a nice warning while also failing
    -// overload resolution nicely. But with -Werror the warning becomes an error,
    -// and we can't explain why overload resolution is failing with extra
    -// information in that error message.
    -//
    -// #pragma GCC diagnostic push
    -// #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    -// static_assert(!std::is_constructible_v<
    -//     FnOnceBox,
    -//     decltype([]() {
    -//       return sus_bind0([i = int(1)]() mutable {++i;});
    -//     }())
    -// >);
    -// #pragma GCC diagnostic pop
    -
    -template 
    -concept can_run = requires(Arg arg, FnOnceBox fnonce,
    -                           FnMutBox fnmut, FnBox fn) {
    -  { static_cast&&>(fnonce)(sus::forward(arg)) };
    -  { static_cast&&>(fnmut)(sus::forward(arg)) };
    -  { static_cast&&>(fn)(sus::forward(arg)) };
    -};
    -// clang-format on
    -
    -// Int is copyable, so references are copied when passed.
    -static_assert(can_run);
    -static_assert(can_run);
    -static_assert(can_run);
    -static_assert(can_run);
    -static_assert(can_run);
    -static_assert(can_run);
    -// But for a move-only type, it can only be passed along as a reference or an
    -// rvalue.
    -static_assert(can_run);
    -static_assert(can_run);
    -static_assert(!can_run);
    -static_assert(!can_run);
    -static_assert(!can_run);
    -static_assert(!can_run);
    -static_assert(can_run);
    -static_assert(can_run);
    -static_assert(can_run);
    -static_assert(!can_run);
    -
    -// Receiving a mutable reference means it must be passed as a mutable reference.
    -static_assert(can_run);
    -static_assert(!can_run);
    -static_assert(!can_run);
    -
    -// Receiving a const reference means it must be passed as a reference.
    -static_assert(can_run);
    -static_assert(can_run);
    -static_assert(!can_run);
    -static_assert(!can_run);
    -static_assert(!can_run);
    -static_assert(!can_run);
    -
    -TEST(FnBox, Pointer) {
    -  {
    -    auto fn = FnOnceBox([](int a, int b) { return a * 2 + b; });
    -    EXPECT_EQ(sus::move(fn)(1, 2), 4);
    -  }
    -  {
    -    auto fn = FnMutBox([](int a, int b) { return a * 2 + b; });
    -    EXPECT_EQ(fn(1, 2), 4);
    -  }
    -  {
    -    auto fn = FnBox([](int a, int b) { return a * 2 + b; });
    -    EXPECT_EQ(sus::move(fn)(1, 2), 4);
    -  }
    -}
    -
    -TEST(FnBox, InlineCapture) {
    -  {
    -    auto fn =
    -        FnOnceBox(sus_bind0([a = 1](int b) { return a * 2 + b; }));
    -    EXPECT_EQ(sus::move(fn)(2), 4);
    -  }
    -  {
    -    auto fn =
    -        FnMutBox(sus_bind0([a = 1](int b) { return a * 2 + b; }));
    -    EXPECT_EQ(sus::move(fn)(2), 4);
    -  }
    -  {
    -    auto fn = FnBox(sus_bind0([a = 1](int b) { return a * 2 + b; }));
    -    EXPECT_EQ(sus::move(fn)(2), 4);
    -  }
    -}
    -
    -TEST(FnBox, OutsideCapture) {
    -  int a = 1;
    -  {
    -    auto fn = FnOnceBox(
    -        sus_bind(sus_store(a), [a](int b) { return a * 2 + b; }));
    -    EXPECT_EQ(sus::move(fn)(2), 4);
    -  }
    -  {
    -    auto fn = FnMutBox(
    -        sus_bind(sus_store(a), [a](int b) { return a * 2 + b; }));
    -    EXPECT_EQ(sus::move(fn)(2), 4);
    -  }
    -  {
    -    auto fn = FnBox(
    -        sus_bind(sus_store(a), [a](int b) { return a * 2 + b; }));
    -    EXPECT_EQ(sus::move(fn)(2), 4);
    -  }
    -}
    -
    -TEST(FnBox, BothCapture) {
    -  int a = 1;
    -  {
    -    auto fn = FnOnceBox(
    -        sus_bind(sus_store(a), [a, b = 2]() { return a * 2 + b; }));
    -    EXPECT_EQ(sus::move(fn)(), 4);
    -  }
    -  {
    -    auto fn = FnMutBox(
    -        sus_bind(sus_store(a), [a, b = 2]() { return a * 2 + b; }));
    -    EXPECT_EQ(sus::move(fn)(), 4);
    -  }
    -  {
    -    auto fn = FnBox(
    -        sus_bind(sus_store(a), [a, b = 2]() { return a * 2 + b; }));
    -    EXPECT_EQ(sus::move(fn)(), 4);
    -  }
    -}
    -
    -TEST(FnBox, CopyFromCapture) {
    -  auto c = Copyable(1);
    -  {
    -    auto fn = FnOnceBox(
    -        sus_bind(sus_store(c), [c](int b) { return c.i * 2 + b; }));
    -    EXPECT_EQ(sus::move(fn)(2), 4);
    -  }
    -  {
    -    auto fn = FnMutBox(
    -        sus_bind(sus_store(c), [c](int b) { return c.i * 2 + b; }));
    -    EXPECT_EQ(sus::move(fn)(2), 4);
    -  }
    -  {
    -    auto fn = FnBox(
    -        sus_bind(sus_store(c), [c](int b) { return c.i * 2 + b; }));
    -    EXPECT_EQ(sus::move(fn)(2), 4);
    -  }
    -}
    -
    -TEST(FnBox, MoveFromCapture) {
    -  {
    -    auto m = MoveOnly(1);
    -    auto fn = FnOnceBox(sus_bind_mut(
    -        sus_store(sus_take(m)),
    -        [m = static_cast(m)](int b) { return m.i * 2 + b; }));
    -    EXPECT_EQ(sus::move(fn)(2), 4);
    -  }
    -  {
    -    auto m = MoveOnly(1);
    -    auto fn = FnMutBox(sus_bind_mut(
    -        sus_store(sus_take(m)),
    -        [m = static_cast(m)](int b) { return m.i * 2 + b; }));
    -    EXPECT_EQ(fn(2), 4);
    -    // The stored value was moved into the run lambda (so `m` holds `-1`).
    -    EXPECT_EQ(m.i, -1);
    -    EXPECT_EQ(fn(-2), -4);
    -    EXPECT_EQ(sus::move(fn)(-2), -4);
    -  }
    -  // Can't hold sus_bind_mut() in FnBox.
    -}
    -
    -TEST(FnBox, MoveIntoCapture) {
    -  {
    -    auto m = MoveOnly(1);
    -    auto fn = FnOnceBox(
    -        sus_bind(sus_store(sus_take(m)), [&m](int b) { return m.i * 2 + b; }));
    -    EXPECT_EQ(sus::move(fn)(2), 4);
    -  }
    -  {
    -    auto m = MoveOnly(1);
    -    auto fn = FnMutBox(
    -        sus_bind(sus_store(sus_take(m)), [&m](int b) { return m.i * 2 + b; }));
    -    EXPECT_EQ(fn(2), 4);
    -    EXPECT_EQ(fn(2), 4);
    -  }
    -  // Can modify the captured m with sus_bind_mut().
    -  {
    -    auto m = MoveOnly(1);
    -    auto fn = FnMutBox(sus_bind_mut(
    -        sus_store(sus_take(m)), [&m](int b) { return m.i++ * 2 + b; }));
    -    EXPECT_EQ(fn(2), 4);
    -    EXPECT_EQ(fn(2), 6);
    -  }
    -  {
    -    auto m = MoveOnly(1);
    -    auto fn = FnBox(
    -        sus_bind(sus_store(sus_take(m)), [&m](int b) { return m.i * 2 + b; }));
    -    EXPECT_EQ(fn(2), 4);
    -    EXPECT_EQ(fn(2), 4);
    -  }
    -}
    -
    -TEST(FnBox, MoveFnBox) {
    -  {
    -    auto fn = FnOnceBox([](int a, int b) { return a * 2 + b; });
    -    auto fn2 = sus::move(fn);
    -    EXPECT_EQ(sus::move(fn2)(1, 2), 4);
    -  }
    -  {
    -    auto fn =
    -        FnOnceBox(sus_bind0([a = 1](int b) { return a * 2 + b; }));
    -    auto fn2 = sus::move(fn);
    -    EXPECT_EQ(sus::move(fn2)(2), 4);
    -  }
    -  {
    -    auto fn = FnMutBox([](int a, int b) { return a * 2 + b; });
    -    auto fn2 = sus::move(fn);
    -    EXPECT_EQ(sus::move(fn2)(1, 2), 4);
    -  }
    -  {
    -    auto fn =
    -        FnMutBox(sus_bind0([a = 1](int b) { return a * 2 + b; }));
    -    auto fn2 = sus::move(fn);
    -    EXPECT_EQ(sus::move(fn2)(2), 4);
    -  }
    -  {
    -    auto fn = FnBox([](int a, int b) { return a * 2 + b; });
    -    auto fn2 = sus::move(fn);
    -    EXPECT_EQ(sus::move(fn2)(1, 2), 4);
    -  }
    -  {
    -    auto fn = FnBox(sus_bind0([a = 1](int b) { return a * 2 + b; }));
    -    auto fn2 = sus::move(fn);
    -    EXPECT_EQ(sus::move(fn2)(2), 4);
    -  }
    -}
    -
    -TEST(FnBox, FnBoxIsFnMutBox) {
    -  {
    -    auto fn = FnBox([](int a, int b) { return a * 2 + b; });
    -    auto mut = FnMutBox(sus::move(fn));
    -    EXPECT_EQ(mut(1, 2), 4);
    -  }
    -  {
    -    auto fn = FnBox(sus_bind0([a = 1](int b) { return a * 2 + b; }));
    -    auto mut = FnMutBox(sus::move(fn));
    -    EXPECT_EQ(mut(2), 4);
    -  }
    -}
    -
    -TEST(FnBox, FnBoxIsFnOnceBox) {
    -  {
    -    auto fn = FnBox([](int a, int b) { return a * 2 + b; });
    -    auto once = FnOnceBox(sus::move(fn));
    -    EXPECT_EQ(sus::move(once)(1, 2), 4);
    -  }
    -  {
    -    auto fn = FnBox(sus_bind0([a = 1](int b) { return a * 2 + b; }));
    -    auto once = FnOnceBox(sus::move(fn));
    -    EXPECT_EQ(sus::move(once)(2), 4);
    -  }
    -}
    -
    -TEST(FnBox, FnMutBoxIsFnOnceBox) {
    -  {
    -    auto fn = FnMutBox([](int a, int b) { return a * 2 + b; });
    -    auto once = FnOnceBox(sus::move(fn));
    -    EXPECT_EQ(sus::move(once)(1, 2), 4);
    -  }
    -  {
    -    auto fn =
    -        FnMutBox(sus_bind0([a = 1](int b) { return a * 2 + b; }));
    -    auto once = FnOnceBox(sus::move(fn));
    -    EXPECT_EQ(sus::move(once)(2), 4);
    -  }
    -}
    -
    -TEST(FnBox, BindUnsafePointer) {
    -  int a = 1;
    -  int* pa = &a;
    -  int b = 2;
    -  auto fn =
    -      FnBox(sus_bind(sus_store(sus_unsafe_pointer(pa), b), [pa, b]() {
    -        // sus_bind() will store pointers as const.
    -        static_assert(std::is_const_v>);
    -        return *pa * 2 + b;
    -      }));
    -  EXPECT_EQ(fn(), 4);
    -
    -  auto fnmut = FnMutBox(
    -      sus_bind_mut(sus_store(sus_unsafe_pointer(pa), b), [pa, b]() {
    -        // sus_bind_mut() will store pointers as mutable.
    -        static_assert(!std::is_const_v>);
    -        return (*pa)++ * 2 + b;
    -      }));
    -  EXPECT_EQ(fnmut(), 4);
    -}
    -
    -TEST(FnBox, Into) {
    -  auto into_fnonce = []> F>(F into_f) {
    -    FnOnceBox f = sus::move_into(into_f);
    -    return sus::move(f)(1);
    -  };
    -  EXPECT_EQ(into_fnonce([](int i) { return i + 1; }), 2);
    -  EXPECT_EQ(into_fnonce(sus_bind0([](int i) { return i + 1; })), 2);
    -
    -  auto into_fnmut = []> F>(F into_f) {
    -    return FnMutBox::from(::sus::move(into_f))(1);
    -  };
    -  EXPECT_EQ(into_fnmut([](int i) { return i + 1; }), 2);
    -  EXPECT_EQ(into_fnmut(sus_bind0([](int i) { return i + 1; })), 2);
    -
    -  auto into_fn = []> F>(F into_f) {
    -    FnBox f = sus::move_into(into_f);
    -    return sus::move(f)(1);
    -  };
    -  EXPECT_EQ(into_fn([](int i) { return i + 1; }), 2);
    -  EXPECT_EQ(into_fn(sus_bind0([](int i) { return i + 1; })), 2);
    -}
    -
    -TEST(FnBoxDeathTest, NullPointer) {
    -  void (*f)() = nullptr;
    -#if GTEST_HAS_DEATH_TEST
    -  EXPECT_DEATH(FnOnceBox::from(f), "");
    -#endif
    -#if GTEST_HAS_DEATH_TEST
    -  EXPECT_DEATH(FnMutBox::from(f), "");
    -#endif
    -#if GTEST_HAS_DEATH_TEST
    -  EXPECT_DEATH(FnBox::from(f), "");
    -#endif
    -}
    -
    -TEST(FnBoxDeathTest, CallAfterMoveConstruct) {
    -  {
    -    auto x = FnOnceBox::from([]() {});
    -    [[maybe_unused]] auto y = sus::move(x);
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -  }
    -  {
    -    auto x = FnMutBox::from([]() {});
    -    [[maybe_unused]] auto y = sus::move(x);
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(x(), "");
    -#endif
    -  }
    -  {
    -    auto x = FnBox::from([]() {});
    -    [[maybe_unused]] auto y = sus::move(x);
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(x(), "");
    -#endif
    -  }
    -  {
    -    auto x = FnOnceBox::from(sus_bind0([]() {}));
    -    [[maybe_unused]] auto y = sus::move(x);
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -  }
    -  {
    -    auto x = FnMutBox::from(sus_bind0([]() {}));
    -    [[maybe_unused]] auto y = sus::move(x);
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(x(), "");
    -#endif
    -  }
    -  {
    -    auto x = FnBox::from(sus_bind0([]() {}));
    -    [[maybe_unused]] auto y = sus::move(x);
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(x(), "");
    -#endif
    -  }
    -}
    -
    -TEST(FnBoxDeathTest, CallAfterMoveAssign) {
    -  {
    -    auto x = FnOnceBox::from([]() {});
    -    auto y = FnOnceBox::from([]() {});
    -    y = sus::move(x);
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -  }
    -  {
    -    auto x = FnMutBox::from([]() {});
    -    auto y = FnOnceBox::from([]() {});
    -    y = sus::move(x);
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(x(), "");
    -#endif
    -  }
    -  {
    -    auto x = FnBox::from([]() {});
    -    auto y = FnOnceBox::from([]() {});
    -    y = sus::move(x);
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(x(), "");
    -#endif
    -  }
    -  {
    -    auto x = FnOnceBox::from(sus_bind0([]() {}));
    -    auto y = FnOnceBox::from([]() {});
    -    y = sus::move(x);
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -  }
    -  {
    -    auto x = FnMutBox::from(sus_bind0([]() {}));
    -    auto y = FnOnceBox::from([]() {});
    -    y = sus::move(x);
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(x(), "");
    -#endif
    -  }
    -  {
    -    auto x = FnBox::from(sus_bind0([]() {}));
    -    auto y = FnOnceBox::from([]() {});
    -    y = sus::move(x);
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(x(), "");
    -#endif
    -  }
    -}
    -
    -TEST(FnBoxDeathTest, CallAfterCall) {
    -  {
    -    auto x = FnOnceBox::from([]() {});
    -    sus::move(x)();
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -  }
    -  {
    -    auto x = FnMutBox::from([]() {});
    -    sus::move(x)();
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -  }
    -  {
    -    auto x = FnBox::from([]() {});
    -    sus::move(x)();
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -  }
    -  {
    -    auto x = FnOnceBox::from(sus_bind0([]() {}));
    -    sus::move(x)();
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -  }
    -  {
    -    auto x = FnMutBox::from(sus_bind0([]() {}));
    -    sus::move(x)();
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -  }
    -  {
    -    auto x = FnBox::from(sus_bind0([]() {}));
    -    sus::move(x)();
    -#if GTEST_HAS_DEATH_TEST
    -    EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -  }
    -}
    -
    -struct Class {
    -  Class(i32 value) : value_(value) {}
    -  i32 value() const { return value_; }
    -
    - private:
    -  i32 value_;
    -};
    -
    -TEST(FnBox, Method) {
    -  auto it = sus::Option(Class(42)).into_iter().map(&Class::value);
    -  sus::check(it.next() == sus::some(42));
    -}
    -
    -}  // namespace
    diff --git a/sus/fn/fn_concepts.h b/sus/fn/fn_concepts.h
    index fdd7aed80..1520aa1cd 100644
    --- a/sus/fn/fn_concepts.h
    +++ b/sus/fn/fn_concepts.h
    @@ -26,27 +26,34 @@
     
     namespace sus::fn {
     
    -/// When used as the return type of the function signature in `Fn`, `FnMut` and
    -/// `FnOnce`, the concepts will match against any return type from a functor
    -/// except `void`.
    +/// When used as the return type of the function signature in
    +/// [`Fn`]($sus::fn::Fn), [`FnMut`]($sus::fn::FnMut) and
    +/// [`FnOnce`]($sus::fn::FnOnce), the concepts will match against any return
    +/// type from a functor except `void`.
    +///
    +/// Use [`Anything`]($sus::fn::Anything) to include `void` as an accepted return
    +/// type.
     struct NonVoid {
       template 
       constexpr NonVoid(T&&) noexcept {}
     };
     
    -/// When used as the return type of the function signature in `Fn`, `FnMut` and
    -/// `FnOnce`, the concepts will match against any return type from a functor
    -/// including `void`.
    +/// When used as the return type of the function signature in
    +/// [`Fn`]($sus::fn::Fn), [`FnMut`]($sus::fn::FnMut) and
    +/// [`FnOnce`]($sus::fn::FnOnce), the concepts will match against any return
    +/// type from a functor including `void`.
    +///
    +/// Use [`NonVoid`]($sus::fn::NonVoid) to exclude `void` as an accepted return
    +/// type.
     struct Anything {
       template 
       constexpr Anything(T&&) noexcept {}
     };
     
    -/// The version of a callable object that is called on an rvalue (moved-from)
    -/// receiver. A `FnOnce` is typically the best fit for any callable that will
    -/// only be called at most once. However when a template (or constexpr) is not
    -/// required, receiving a `FnOnceRef` instead of `FnOnce auto&&` will typically
    -/// produce less code by using type erasure to avoid template instantiation.
    +/// The version of a callable object that may be called only once.
    +///
    +/// A `FnOnce` is typically the best fit for any callable that will
    +/// only be called at most once.
     ///
     /// A type that satisfies `FnOnce` will return a type that can be converted to
     /// `R` when called with the arguments `Args...`. `FnOnce` is satisfied by
    @@ -68,11 +75,15 @@ struct Anything {
     /// an lvalue in the caller.
     ///
     /// A `FnOnce` should be called by moving it with `sus::move()` when passing it
    -/// to `sus::fn::call_once()` along with any arguments. It is moved-from after
    -/// calling, and it should only be called once.
    -///
    -/// Calling a `FnOnce` multiple times may panic or cause Undefined Behaviour.
    -/// Not moving the `FnOnce` when calling it may fail to compile, panic, or cause
    +/// to `sus::fn::call_once()` along with any arguments. This ensures the
    +/// correct overload is called on the object and that method pointers are
    +/// called correctly. It is moved-from after calling, and it should only be
    +/// called once.
    +///
    +/// Calling a `FnOnce` multiple times may [`panic`]($sus::assertions::panic)
    +/// or cause Undefined Behaviour.
    +/// Not moving the `FnOnce` when calling it may fail to compile,
    +/// [`panic`]($sus::assertions::panic), or cause
     /// Undefined Behaviour depending on the type that is being used to satisfy
     /// `FnOnce`.
     ///
    @@ -83,15 +94,6 @@ struct Anything {
     /// well, `FnOnce` is allowed to mutate internal state, but it does not have to,
     /// which is compatible with the const nature of `Fn`.
     ///
    -/// # Subspace types that satisfy `FnOnce`
    -/// The `FnOnceRef` and `FnOnceBox` types in the Subspace library satisfy
    -/// `FnOnce`. They must be moved from when called, and they panic if called more
    -/// than once, as that implies a use-after-move.
    -///
    -/// Like the concepts, `FnRef` is convertible to `FnMutRef` is convertible to
    -/// `FnOnceRef`. And `FnBox` is convertible to `FnMutBox` is convertible to
    -/// `FnOnceBox`.
    -///
     /// # Examples
     /// A function that receives a `FnOnce` matching type and calls it:
     /// ```
    @@ -154,12 +156,10 @@ concept FnOnce = requires {
     };
     
     /// The version of a callable object that is allowed to mutate internal state
    -/// and may be called multiple times. A `FnMut` is typically the best fit for
    -/// any callable that may be called one or more times. However when a template
    -/// (or constexpr) is not required, receiving a `FnMutRef` instead of `FnMut
    -/// auto` will typically produce less code by using type erasure to avoid
    -/// template instantiation.
    +/// and may be called multiple times.
     ///
    +/// A `FnMut` is typically the best fit for any callable that may be called one
    +/// or more times.
     /// Because a `FnMut` is able to mutate internal state, it may return different
     /// values each time it is called with the same inputs.
     ///
    @@ -178,13 +178,13 @@ concept FnOnce = requires {
     /// ```
     ///
     /// # Use of `FnMut`
    -/// `FnMut` should be received by value typically. If received as a rvalue
    -/// (universal) reference, it should be constrained by
    -/// [`IsMoveRef`]($sus::mem::IsMoveRef) to avoid moving out of
    -/// an lvalue in the caller.
    +/// `FnMut` should be received by value typically, though it can be received by
    +/// reference if mutations should be visible to the caller.
     ///
     /// A `FnMut` should be called by passing it to `sus::fn::call_mut()` along with
    -/// any arguments. A `FnMut` may be called any number of times, unlike `FnOnce`,
    +/// any arguments. This ensures the correct overload is called on the object and
    +/// that method pointers are called correctly.
    +/// A `FnMut` may be called any number of times, unlike `FnOnce`,
     /// and should not be moved when called.
     ///
     /// # Compatibility
    @@ -194,15 +194,6 @@ concept FnOnce = requires {
     /// well, `FnOnce` is allowed to mutate internal state, but it does not have to,
     /// which is compatible with the const nature of `Fn`.
     ///
    -/// # Subspace types that satisfy `FnMut`
    -/// The `FnMutRef` and `FnMutBox` types in the Subspace library satisfy `FnMut`
    -/// (and thus `FnOnce` as well). They may be called any number of times and are
    -/// able to mutate internal state.
    -///
    -/// Like the concepts, `FnRef` is convertible to `FnMutRef` is convertible to
    -/// `FnOnceRef`. And `FnBox` is convertible to `FnMutBox` is convertible to
    -/// `FnOnceBox`.
    -///
     /// # Examples
     /// A function that receives a `FnMut` matching type and calls it:
     /// ```
    @@ -268,27 +259,27 @@ concept FnMut = requires {
     };
     
     /// The version of a callable object that may be called multiple times without
    -/// mutating internal state. A `Fn` is useful for a callable that is received as
    -/// a const reference to indicate it and may be called one or more times and
    -/// does not change between call. However when a template (or constexpr) is not
    -/// required, receiving a `FnRef` instead of `const Fn auto&` will typically
    -/// produce less code by using type erasure to avoid template instantiation.
    +/// mutating internal state.
     ///
    -/// Because a `FnMut` is able to mutate internal state, it may return different
    -/// values each time it is called with the same inputs.
    +/// A `Fn` is useful for a callable that is expected to be called one or more
    +/// times and whose results do not change between calls. This is of course
    +/// possible to violate with `mutable` or global state, but it is discouraged
    +/// as it violates the `Fn` protocol expectations of the caller.
    +/// [`FnMut`]($sus::fn::FnMut) should be used when the function will
    +/// mutate anything and can return different values as a result.
     ///
    -/// A type that satisfies `FnMut` will return a type that can be converted to
    -/// `R` when called with the arguments `Args...`. `FnMut` is satisfied by
    -/// being callable as an lvalue (which is done by providing an operator() that
    -/// is not `&&`-qualified). Mutable and const lambdas will satisfy
    -/// `FnMut`.
    +/// A type that satisfies `Fn` will return a type that can be converted to
    +/// `R` when called with the arguments `Args...`. `Fn` is satisfied by
    +/// being callable as a const lvalue (which is done by providing an operator()
    +/// that is `const`- or `const&`-qualified). Const lambdas will satisfy
    +/// `Fn` but mutable ones will not.
     ///
     /// The second argument of `Fn` is a function signature with the format
     /// `ReturnType(Args...)`, where `Args...` are the arguments that will be passed
     /// to the `Fn` and `ReturnType` is what is expected to be received back. It
     /// would appear as a matching concept as:
     /// ```
    -/// void function(const Fn auto& f) { ... }
    +/// void function(Fn auto f) { ... }
     /// ```
     ///
     /// # Use of `Fn`
    @@ -296,9 +287,10 @@ concept FnMut = requires {
     /// const reference.
     ///
     /// A `Fn` should be called by passing it to `std::fn::call()` along with any
    -/// arguments. This ensures the correct overload is called on the object. A `Fn`
    -/// may be called any number of times, unlike `FnOnce`, and should not be moved
    -/// when called.
    +/// arguments. This ensures the correct overload is called on the object and
    +/// that method pointers are called correctly.
    +/// A `Fn` may be called any number of times, unlike `FnOnce`, and should not
    +/// be moved when called.
     ///
     /// # Compatibility
     /// Any callable type that satisfies `Fn` will also satisfy `FnMut` and
    @@ -307,21 +299,12 @@ concept FnMut = requires {
     /// are able to mutate state when run, they are not required to and a constant
     /// `Fn` satisfies them.
     ///
    -/// # Subspace types that satisfy `FnMut`
    -/// The `FnRef` and `FnBox` types in the Subspace library satisfy `Fn` (and thus
    -/// `FnMut` and `FnOnce` as well). They may be called any number of times and
    -/// are callable as a const object.
    -///
    -/// Like the concepts, `FnRef` is convertible to `FnMutRef` is convertible to
    -/// `FnOnceRef`. And `FnBox` is convertible to `FnMutBox` is convertible to
    -/// `FnOnceBox`.
    -///
     /// # Examples
     /// A function that receives a `Fn` matching type and calls it:
     /// ```
     /// // Accepts any type that can be called once with (Option) and returns
     /// // i32.
    -/// static i32 do_stuff(const sus::fn::Fn)> auto& f) {
    +/// static i32 do_stuff(sus::fn::Fn)> auto f) {
     ///   return sus::fn::call(f, sus::some(400)) +
     ///          sus::fn::call(f, sus::some(100));
     /// }
    @@ -380,11 +363,11 @@ concept Fn = requires {
       requires FnOnce;
     };
     
    -/// Invokes the `FnOnce`, passing any given arguments along, and returning the
    -/// result.
    +/// Invokes the [`FnOnce`]($sus::fn::FnOnce), passing any given arguments along,
    +/// and returning the result.
     ///
     /// This function is like
    -/// [`std::invoke()`](https://en.cppreference.com/w/cpp/utility/functional/invoke)
    +/// [`std::invoke`](https://en.cppreference.com/w/cpp/utility/functional/invoke)
     /// but it provides the following additional guiderails:
     /// * Verifies that the thing being invoked is being moved from so that the
     ///   correct overload will be invoked.
    @@ -395,11 +378,11 @@ sus_always_inline constexpr decltype(auto) call_once(F&& f, Args&&... args)
       return std::invoke(sus::move(f), sus::forward(args)...);
     }
     
    -/// Invokes the `FnMut`, passing any given arguments along, and returning the
    -/// result.
    +/// Invokes the [`FnMut`]($sus::fn::FnMut), passing any given arguments along,
    +/// and returning the result.
     ///
     /// This function is like
    -/// [`std::invoke()`](https://en.cppreference.com/w/cpp/utility/functional/invoke)
    +/// [`std::invoke`](https://en.cppreference.com/w/cpp/utility/functional/invoke)
     /// but it provides the following additional guiderails:
     /// * Verifies that the thing being invoked is called as a mutable lvalue so
     ///   that the correct overload will be invoked.
    @@ -410,11 +393,11 @@ sus_always_inline constexpr decltype(auto) call_mut(F&& f, Args&&... args) {
                          sus::forward(args)...);
     }
     
    -/// Invokes the `Fn`, passing any given arguments along, and returning the
    -/// result.
    +/// Invokes the [`Fn`]($sus::fn::Fn), passing any given arguments along,
    +/// and returning the result.
     ///
     /// This function is like
    -/// [`std::invoke()`](https://en.cppreference.com/w/cpp/utility/functional/invoke)
    +/// [`std::invoke`](https://en.cppreference.com/w/cpp/utility/functional/invoke)
     /// but it provides the following additional guiderails:
     /// * Verifies that the thing being invoked is called as a const lvalue so
     ///   that the correct overload will be invoked.
    diff --git a/sus/fn/fn_dyn.h b/sus/fn/fn_dyn.h
    new file mode 100644
    index 000000000..2244c9390
    --- /dev/null
    +++ b/sus/fn/fn_dyn.h
    @@ -0,0 +1,176 @@
    +// Copyright 2023 Google LLC
    +//
    +// Licensed under the Apache License, Version 2.0 (the "License");
    +// you may not use this file except in compliance with the License.
    +// You may obtain a copy of the License at
    +//
    +//     https://www.apache.org/licenses/LICENSE-2.0
    +//
    +// Unless required by applicable law or agreed to in writing, software
    +// distributed under the License is distributed on an "AS IS" BASIS,
    +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +// See the License for the specific language governing permissions and
    +// limitations under the License.
    +
    +// IWYU pragma: private, include "sus/fn/fn.h"
    +// IWYU pragma: friend "sus/.*"
    +#pragma once
    +
    +#include "sus/boxed/dyn.h"
    +#include "sus/fn/fn_concepts.h"
    +
    +namespace sus::fn {
    +
    +template 
    +struct DynFn;
    +template 
    +struct DynFnMut;
    +template 
    +struct DynFnOnce;
    +
    +template 
    +  requires(Fn)
    +struct DynFnTyped;
    +template 
    +  requires(FnMut)
    +struct DynFnMutTyped;
    +template 
    +  requires(FnOnce)
    +struct DynFnOnceTyped;
    +
    +/// A type-erased object which satisifies the concept [`Fn`](
    +/// $sus::fn::Fn).
    +///
    +/// See [`DynConcept`]($sus::boxed::DynConcept) for more on type erasure of
    +/// concept-satisfying types.
    +template 
    +struct DynFn {
    +  template 
    +  static constexpr bool SatisfiesConcept = Fn;
    +  template 
    +  using DynTyped = DynFnTyped;
    +
    +  static constexpr bool IsDynFn = true;
    +
    +  DynFn() = default;
    +  virtual ~DynFn() = default;
    +  DynFn(DynFn&&) = delete;
    +  DynFn& operator=(DynFn&&) = delete;
    +
    +  // Virtual concept API.
    +  virtual R operator()(Args&&...) const = 0;
    +};
    +
    +/// The implementation of type-erasure for the Fn concept.
    +/// #[doc.hidden]
    +template 
    +  requires(Fn)
    +struct DynFnTyped final : public DynFn {
    +  constexpr DynFnTyped(Store&& c) : c_(sus::forward(c)) {}
    +
    +  R operator()(Args&&... args) const override {
    +    return sus::fn::call(c_, ::sus::forward(args)...);
    +  }
    +
    + private:
    +  Store c_;
    +};
    +
    +/// A type-erased object which satisifies the concept [`FnMut`](
    +/// $sus::fn::FnMut).
    +///
    +/// See [`DynConcept`]($sus::boxed::DynConcept) for more on type erasure of
    +/// concept-satisfying types.
    +template 
    +struct DynFnMut {
    +  template 
    +  static constexpr bool SatisfiesConcept = FnMut;
    +  template 
    +  using DynTyped = DynFnMutTyped;
    +
    +  static constexpr bool IsDynFn = true;
    +
    +  DynFnMut() = default;
    +  virtual ~DynFnMut() = default;
    +  DynFnMut(DynFnMut&&) = delete;
    +  DynFnMut& operator=(DynFnMut&&) = delete;
    +
    +  // Virtual concept API.
    +  virtual R operator()(Args&&...) = 0;
    +};
    +
    +/// The implementation of type-erasure for the DynFnMut concept.
    +/// #[doc.hidden]
    +template 
    +  requires(FnMut)
    +struct DynFnMutTyped final : public DynFnMut {
    +  constexpr DynFnMutTyped(Store&& c) : c_(sus::forward(c)) {}
    +
    +  R operator()(Args&&... args) override {
    +    return call_mut(c_, ::sus::forward(args)...);
    +  }
    +
    + private:
    +  Store c_;
    +};
    +
    +/// A type-erased object which satisifies the concept [`FnOnce`](
    +/// $sus::fn::FnOnce).
    +///
    +/// See [`DynConcept`]($sus::boxed::DynConcept) for more on type erasure of
    +/// concept-satisfying types.
    +template 
    +struct DynFnOnce {
    +  template 
    +  static constexpr bool SatisfiesConcept = FnOnce;
    +  template 
    +  using DynTyped = DynFnOnceTyped;
    +
    +  static constexpr bool IsDynFn = true;
    +
    +  DynFnOnce() = default;
    +  virtual ~DynFnOnce() = default;
    +  DynFnOnce(DynFnOnce&&) = delete;
    +  DynFnOnce& operator=(DynFnOnce&&) = delete;
    +
    +  // Virtual concept API.
    +  virtual R operator()(Args&&...) && = 0;
    +};
    +
    +/// The implementation of type-erasure for the DynFnOnce concept.
    +/// #[doc.hidden]
    +template 
    +  requires(FnOnce)
    +struct DynFnOnceTyped final : public DynFnOnce {
    +  constexpr DynFnOnceTyped(Store&& c) : c_(sus::forward(c)) {}
    +
    +  R operator()(Args&&... args) && override {
    +    return call_once(::sus::move(c_), ::sus::forward(args)...);
    +  }
    +
    + private:
    +  Store c_;
    +};
    +
    +// `DynFn` satisfies `Fn`.
    +static_assert(Fn, int(double)>);
    +// `DynFn` satisfies `DynConcept`, meaning it type-erases correctly and can
    +// interact with `Dyn` and `Box`.
    +static_assert(::sus::boxed::DynConcept,
    +                                       decltype([](float) { return 0; })>);
    +
    +// `DynFnMut` satisfies `FnMut`.
    +static_assert(FnMut, int(double)>);
    +// `DynFnMut` satisfies `DynConcept`, meaning it type-erases correctly and can
    +// interact with `Dyn` and `Box`.
    +static_assert(::sus::boxed::DynConcept,
    +                                       decltype([](float) { return 0; })>);
    +
    +// `DynFnOnce` satisfies `FnOnce`.
    +static_assert(FnOnce, int(double)>);
    +// `DynFnOnce` satisfies `DynConcept`, meaning it type-erases correctly and can
    +// interact with `Dyn` and `Box`.
    +static_assert(::sus::boxed::DynConcept,
    +                                       decltype([](float) { return 0; })>);
    +
    +}  // namespace sus::fn
    diff --git a/sus/fn/fn_dyn_unittest.cc b/sus/fn/fn_dyn_unittest.cc
    new file mode 100644
    index 000000000..29ccc9433
    --- /dev/null
    +++ b/sus/fn/fn_dyn_unittest.cc
    @@ -0,0 +1,80 @@
    +// Copyright 2023 Google LLC
    +//
    +// Licensed under the Apache License, Version 2.0 (the "License");
    +// you may not use this file except in compliance with the License.
    +// You may obtain a copy of the License at
    +//
    +//     https://www.apache.org/licenses/LICENSE-2.0
    +//
    +// Unless required by applicable law or agreed to in writing, software
    +// distributed under the License is distributed on an "AS IS" BASIS,
    +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +// See the License for the specific language governing permissions and
    +// limitations under the License.
    +
    +#include "sus/fn/fn_dyn.h"
    +
    +#include "googletest/include/gtest/gtest.h"
    +#include "sus/boxed/box.h"
    +#include "sus/prelude.h"
    +
    +namespace {
    +using namespace sus::fn;
    +
    +TEST(FnDyn, Fn) {
    +  auto x = [](const DynFn& f) { return call(f, 1, 2); };
    +  i32 c = x(sus::dyn>([](i32 a, i32 b) { return a + b; }));
    +  EXPECT_EQ(c, 1 + 2);
    +  i32 d = x(sus::dyn>([](i32 a, i32 b) { return a * b; }));
    +  EXPECT_EQ(d, 1 * 2);
    +}
    +
    +TEST(FnDyn, FnBox) {
    +  auto x = [](sus::Box> f) { return f(1, 2); };
    +  i32 c = x(sus::into([](i32 a, i32 b) { return a + b; }));
    +  EXPECT_EQ(c, 1 + 2);
    +  i32 d = x(sus::into([](i32 a, i32 b) { return a * b; }));
    +  EXPECT_EQ(d, 1 * 2);
    +}
    +
    +TEST(FnMutDyn, FnMut) {
    +  auto x = [](DynFnMut& f) { return call_mut(f, 1, 2); };
    +  i32 c =
    +      x(sus::dyn>([](i32 a, i32 b) { return a + b; }));
    +  EXPECT_EQ(c, 1 + 2);
    +  i32 d =
    +      x(sus::dyn>([](i32 a, i32 b) { return a * b; }));
    +  EXPECT_EQ(d, 1 * 2);
    +}
    +
    +TEST(FnMutDyn, FnMutBox) {
    +  auto x = [](sus::Box> f) { return f(1, 2); };
    +  i32 c = x(sus::into([](i32 a, i32 b) { return a + b; }));
    +  EXPECT_EQ(c, 1 + 2);
    +  i32 d = x(sus::into([](i32 a, i32 b) { return a * b; }));
    +  EXPECT_EQ(d, 1 * 2);
    +}
    +
    +TEST(FnDyn, FnOnce) {
    +  auto x = [](DynFnOnce&& f) {
    +    return call_once(sus::move(f), 1, 2);
    +  };
    +  i32 c =
    +      x(sus::dyn>([](i32 a, i32 b) { return a + b; }));
    +  EXPECT_EQ(c, 1 + 2);
    +  i32 d =
    +      x(sus::dyn>([](i32 a, i32 b) { return a * b; }));
    +  EXPECT_EQ(d, 1 * 2);
    +}
    +
    +TEST(FnOnceDyn, FnOnceBox) {
    +  auto x = [](sus::Box> f) {
    +    return sus::move(f)(1, 2);
    +  };
    +  i32 c = x(sus::into([](i32 a, i32 b) { return a + b; }));
    +  EXPECT_EQ(c, 1 + 2);
    +  i32 d = x(sus::into([](i32 a, i32 b) { return a * b; }));
    +  EXPECT_EQ(d, 1 * 2);
    +}
    +
    +}  // namespace
    diff --git a/sus/fn/fn_ref.h b/sus/fn/fn_ref.h
    deleted file mode 100644
    index ee4f220d6..000000000
    --- a/sus/fn/fn_ref.h
    +++ /dev/null
    @@ -1,511 +0,0 @@
    -// Copyright 2022 Google LLC
    -//
    -// Licensed under the Apache License, Version 2.0 (the "License");
    -// you may not use this file except in compliance with the License.
    -// You may obtain a copy of the License at
    -//
    -//     https://www.apache.org/licenses/LICENSE-2.0
    -//
    -// Unless required by applicable law or agreed to in writing, software
    -// distributed under the License is distributed on an "AS IS" BASIS,
    -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    -// See the License for the specific language governing permissions and
    -// limitations under the License.
    -
    -// IWYU pragma: private, include "sus/fn/fn.h"
    -// IWYU pragma: friend "sus/.*"
    -#pragma once
    -
    -#include "sus/assertions/unreachable.h"
    -#include "sus/fn/__private/callable_types.h"
    -#include "sus/fn/__private/fn_ref_invoker.h"
    -#include "sus/lib/__private/forward_decl.h"
    -#include "sus/macros/lifetimebound.h"
    -#include "sus/mem/addressof.h"
    -#include "sus/mem/forward.h"
    -#include "sus/mem/never_value.h"
    -#include "sus/mem/relocate.h"
    -#include "sus/mem/replace.h"
    -
    -namespace sus::fn {
    -
    -/// A closure that erases the type of the internal callable object (lambda). A
    -/// FnMutRef may be called multiple times, and holds a const callable object, so
    -/// it will return the same value each call with the same inputs.
    -///
    -/// FnRef can be used as a FnMutRef, which can be used as a FnOnceRef. Lambdas
    -/// can be converted into a FnOnceRef, FnMutRef, or FnRef directly.
    -///
    -/// FnOnceRef, FnMutRef and FnRef are only safe to appear as lvalues when they
    -/// are a function parameter, and a clang-tidy check is provided to enforce
    -/// this. They only hold a reference to the underlying lambda so they must not
    -/// outlive the lambda.
    -///
    -/// # Why can a "const" FnRef convert to a mutable FnMutRef or FnOnceRef?
    -///
    -/// A FnMutRef or FnOnceRef is _allowed_ to mutate its storage, but a "const"
    -/// FnRef closure would just choose not to do so.
    -///
    -/// However, a `const FnRef` requires that the storage is not mutated, so it is
    -/// not useful if converted to a `const FnMutRef` or `const FnOnceRef` which are
    -/// only callable as mutable objects.
    -///
    -/// # Null pointers
    -///
    -/// A null function pointer is not allowed, constructing a FnOnceRef from a null
    -/// pointer will panic.
    -template 
    -class [[sus_trivial_abi]] FnRef {
    - public:
    -  /// Construction from a function pointer.
    -  ///
    -  /// #[doc.overloads=ctor.fnpointer]
    -  template <__private::FunctionPointer F>
    -  FnRef(F ptr) noexcept {
    -    ::sus::check(ptr != nullptr);
    -    storage_.fnptr = reinterpret_cast(ptr);
    -    invoke_ = &__private::Invoker::template fnptr_call_const;
    -  }
    -
    -  /// Construction from a non-capturing lambda.
    -  ///
    -  /// #[doc.overloads=ctor.lambda]
    -  template <__private::CallableConst F>
    -    requires(__private::ConvertsToFunctionPointer)
    -  constexpr FnRef(F&& object sus_lifetimebound) noexcept {
    -    storage_.object = ::sus::mem::addressof(object);
    -    invoke_ = &__private::Invoker<
    -        std::remove_reference_t>::template object_call_const;
    -  }
    -
    -  /// Construction from a capturing lambda or other callable object.
    -  ///
    -  /// #[doc.overloads=ctor.capturelambda]
    -  template <__private::CallableConst F>
    -    requires(!__private::ConvertsToFunctionPointer)
    -  constexpr FnRef(F&& object sus_lifetimebound) noexcept {
    -    storage_.object = ::sus::mem::addressof(object);
    -    invoke_ = &__private::Invoker<
    -        std::remove_reference_t>::template object_call_const;
    -  }
    -
    -  ~FnRef() noexcept = default;
    -
    -  constexpr FnRef(FnRef&& o) noexcept
    -      : storage_(o.storage_), invoke_(::sus::mem::replace(o.invoke_, nullptr)) {
    -    ::sus::check(invoke_);  // Catch use-after-move.
    -  }
    -  constexpr FnRef& operator=(FnRef&& o) noexcept {
    -    storage_ = o.storage_;
    -    invoke_ = ::sus::mem::replace(o.invoke_, nullptr);
    -    ::sus::check(invoke_);  // Catch use-after-move.
    -    return *this;
    -  }
    -
    -  // Not copyable.
    -  FnRef(const FnRef&) noexcept = delete;
    -  FnRef& operator=(const FnRef&) noexcept = delete;
    -
    -  /// sus::mem::Clone trait.
    -  constexpr FnRef clone() const {
    -    ::sus::check(invoke_);  // Catch use-after-move.
    -    return FnRef(storage_, invoke_);
    -  }
    -
    -  /// Runs the closure.
    -  ///
    -  /// #[doc.overloads=call.const]
    -  inline R operator()(CallArgs... args) const& {
    -    ::sus::check(invoke_);  // Catch use-after-move.
    -    return (*invoke_)(storage_, ::sus::forward(args)...);
    -  }
    -
    -  /// Runs and consumes the closure.
    -  ///
    -  /// #[doc.overloads=call.rvalue]
    -  inline R operator()(CallArgs... args) && {
    -    ::sus::check(invoke_);  // Catch use-after-move.
    -    return (*::sus::mem::replace(invoke_, nullptr))(
    -        storage_, ::sus::forward(args)...);
    -  }
    -
    -  /// `sus::construct::From` trait implementation.
    -  ///
    -  /// FnRef satisfies `From` for the same types that it is constructible
    -  /// from: function pointers that exactly match its own signature, and
    -  /// const-callable objects (lambdas) that are compatible with its signature.
    -  template 
    -    requires(std::constructible_from)
    -  constexpr static auto from(F&& object sus_lifetimebound) noexcept {
    -    return FnRef(::sus::forward(object));
    -  }
    -
    - private:
    -  template 
    -  friend class FnOnceRef;
    -  template 
    -  friend class FnMutRef;
    -
    -  constexpr FnRef(union __private::Storage storage,
    -                  __private::InvokeFnPtr invoke)
    -      : storage_(storage), invoke_(invoke) {}
    -
    -  union __private::Storage storage_;
    -  /// The `invoke_` pointer is set to null to indicate the FnRef is moved-from.
    -  /// It uses another pointer value as its never-value.
    -  __private::InvokeFnPtr invoke_;
    -
    -  // A function pointer to use as a never-value for InvokeFnPointer.
    -  static R invoke_never_value(const union __private::Storage&, CallArgs...) {
    -    sus::unreachable();
    -  }
    -
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn,
    -                                  decltype(storage_.fnptr),
    -                                  decltype(storage_.object), decltype(invoke_));
    -  sus_class_never_value_field(::sus::marker::unsafe_fn, FnRef, invoke_,
    -                              &invoke_never_value, &invoke_never_value);
    -  // For the NeverValueField.
    -  explicit constexpr FnRef(::sus::mem::NeverValueConstructor) noexcept
    -      : invoke_(&invoke_never_value) {}
    -};
    -
    -/// A closure that erases the type of the internal callable object (lambda) that
    -/// may mutate internal state. A FnMutRef may be called multiple times, and may
    -/// return a different value on each call with the same inputs.
    -///
    -/// FnRef can be used as a FnMutRef, which can be used as a FnOnceRef. Lambdas
    -/// can be converted into a FnOnceRef, FnMutRef, or FnRef directly.
    -///
    -/// FnOnceRef, FnMutRef and FnRef are only safe to appear as lvalues when they
    -/// are a function parameter, and a clang-tidy check is provided to enforce
    -/// this. They only hold a reference to the underlying lambda so they must not
    -/// outlive the lambda.
    -///
    -/// # Why can a "const" FnRef convert to a mutable FnMutRef or FnOnceRef?
    -///
    -/// A FnMutRef or FnOnceRef is _allowed_ to mutate its storage, but a "const"
    -/// FnRef closure would just choose not to do so.
    -///
    -/// However, a `const FnRef` requires that the storage is not mutated, so it is
    -/// not useful if converted to a `const FnMutRef` or `const FnOnceRef` which are
    -/// only callable as mutable objects.
    -///
    -/// # Null pointers
    -///
    -/// A null function pointer is not allowed, constructing a FnOnceRef from a null
    -/// pointer will panic.
    -template 
    -class [[sus_trivial_abi]] FnMutRef {
    - public:
    -  /// Construction from a function pointer or captureless lambda.
    -  ///
    -  /// #[doc.overloads=ctor.fnpointer]
    -  template <__private::FunctionPointer F>
    -  FnMutRef(F ptr) noexcept {
    -    ::sus::check(ptr != nullptr);
    -    storage_.fnptr = reinterpret_cast(ptr);
    -    invoke_ = &__private::Invoker::template fnptr_call_mut;
    -  }
    -
    -  /// Construction from a non-capturing lambda.
    -  ///
    -  /// #[doc.overloads=ctor.lambda]
    -  template <__private::CallableMut F>
    -    requires(__private::ConvertsToFunctionPointer)
    -  constexpr FnMutRef(F&& object sus_lifetimebound) noexcept {
    -    storage_.object = ::sus::mem::addressof(object);
    -    invoke_ = &__private::Invoker<
    -        std::remove_reference_t>::template object_call_mut;
    -  }
    -
    -  /// Construction from a capturing lambda or other callable object.
    -  ///
    -  /// #[doc.overloads=ctor.capturelambda]
    -  template <__private::CallableMut F>
    -    requires(!__private::ConvertsToFunctionPointer)
    -  constexpr FnMutRef(F&& object sus_lifetimebound) noexcept {
    -    storage_.object = ::sus::mem::addressof(object);
    -    invoke_ = &__private::Invoker<
    -        std::remove_reference_t>::template object_call_mut;
    -  }
    -
    -  /// Construction from FnRef.
    -  ///
    -  /// Since FnRef is callable, FnMutRef is already constructible from it, but
    -  /// this constructor avoids extra indirections being inserted when converting,
    -  /// since otherwise an extra invoker call would be introduced.
    -  ///
    -  /// #[doc.overloads=ctor.fnref]
    -  constexpr FnMutRef(FnRef&& o sus_lifetimebound) noexcept
    -      : storage_(o.storage_), invoke_(::sus::mem::replace(o.invoke_, nullptr)) {
    -    ::sus::check(invoke_);  // Catch use-after-move.
    -  }
    -
    -  ~FnMutRef() noexcept = default;
    -
    -  constexpr FnMutRef(FnMutRef&& o) noexcept
    -      : storage_(o.storage_), invoke_(::sus::mem::replace(o.invoke_, nullptr)) {
    -    ::sus::check(invoke_);  // Catch use-after-move.
    -  }
    -  constexpr FnMutRef& operator=(FnMutRef&& o) noexcept {
    -    storage_ = o.storage_;
    -    invoke_ = ::sus::mem::replace(o.invoke_, nullptr);
    -    ::sus::check(invoke_);  // Catch use-after-move.
    -    return *this;
    -  }
    -
    -  // Not copyable.
    -  FnMutRef(const FnMutRef&) noexcept = delete;
    -  FnMutRef& operator=(const FnMutRef&) noexcept = delete;
    -
    -  /// sus::mem::Clone trait.
    -  constexpr FnMutRef clone() const {
    -    ::sus::check(invoke_);  // Catch use-after-move.
    -    return FnMutRef(storage_, invoke_);
    -  }
    -
    -  /// Runs the closure.
    -  ///
    -  /// #[doc.overloads=call.mut]
    -  inline R operator()(CallArgs... args) & {
    -    ::sus::check(invoke_);  // Catch use-after-move.
    -    return (*invoke_)(storage_, ::sus::forward(args)...);
    -  }
    -
    -  /// Runs and consumes the closure.
    -  ///
    -  /// #[doc.overloads=call.rvalue]
    -  inline R operator()(CallArgs... args) && {
    -    ::sus::check(invoke_);  // Catch use-after-move.
    -    return (*::sus::mem::replace(invoke_, nullptr))(
    -        storage_, ::sus::forward(args)...);
    -  }
    -
    -  /// `sus::construct::From` trait implementation.
    -  ///
    -  /// FnMutRef satisfies `From` for the same types that it is constructible
    -  /// from: function pointers that exactly match its own signature, and callable
    -  /// objects (lambdas) that are compatible with its signature.
    -  template 
    -    requires(std::constructible_from)
    -  constexpr static auto from(F&& object sus_lifetimebound) noexcept {
    -    return FnMutRef(::sus::forward(object));
    -  }
    -
    - private:
    -  template 
    -  friend class FnOnceRef;
    -
    -  constexpr FnMutRef(union __private::Storage storage,
    -                     __private::InvokeFnPtr invoke)
    -      : storage_(storage), invoke_(invoke) {}
    -
    -  union __private::Storage storage_;
    -  /// The `invoke_` pointer is set to null to indicate the `FnMutRef` is
    -  /// moved-from. It uses another pointer value as its never-value.
    -  __private::InvokeFnPtr invoke_;
    -
    -  // A function pointer to use as a never-value for InvokeFnPointer.
    -  static R invoke_never_value(const union __private::Storage&, CallArgs...) {
    -    sus::unreachable();
    -  }
    -
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn,
    -                                  decltype(storage_.fnptr),
    -                                  decltype(storage_.object), decltype(invoke_));
    -  sus_class_never_value_field(::sus::marker::unsafe_fn, FnMutRef, invoke_,
    -                              &invoke_never_value, &invoke_never_value);
    -  // For the NeverValueField.
    -  explicit constexpr FnMutRef(::sus::mem::NeverValueConstructor) noexcept
    -      : invoke_(&invoke_never_value) {}
    -};
    -
    -/// A closure that erases the type of the internal callable object (lambda). A
    -/// FnOnceRef may only be called a single time.
    -///
    -/// FnRef can be used as a FnMutRef, which can be used as a FnOnceRef. Lambdas
    -/// can be converted into a FnOnceRef, FnMutRef, or FnRef directly.
    -///
    -/// FnOnceRef, FnMutRef and FnRef are only safe to appear as lvalues when they
    -/// are a function parameter, and a clang-tidy check is provided to enforce
    -/// this. They only hold a reference to the underlying lambda so they must not
    -/// outlive the lambda.
    -///
    -/// # Why can a "const" FnRef convert to a mutable FnMutRef or FnOnceRef?
    -///
    -/// A FnMutRef or FnOnceRef is _allowed_ to mutate its storage, but a "const"
    -/// FnRef closure would just choose not to do so.
    -///
    -/// However, a `const FnRef` requires that the storage is not mutated, so it is
    -/// not useful if converted to a `const FnMutRef` or `const FnOnceRef` which are
    -/// only callable as mutable objects.
    -///
    -/// # Null pointers
    -///
    -/// A null function pointer is not allowed, constructing a FnOnceRef from a null
    -/// pointer will panic.
    -template 
    -class [[sus_trivial_abi]] FnOnceRef {
    - public:
    -  /// Construction from a function pointer or captureless lambda.
    -  ///
    -  /// #[doc.overloads=ctor.fnpointer]
    -  template <__private::FunctionPointer F>
    -  FnOnceRef(F ptr) noexcept {
    -    ::sus::check(ptr != nullptr);
    -    storage_.fnptr = reinterpret_cast(ptr);
    -    invoke_ = &__private::Invoker::template fnptr_call_mut;
    -  }
    -
    -  /// Construction from a non-capturing lambda.
    -  ///
    -  /// #[doc.overloads=ctor.lambda]
    -  template <__private::CallableOnceMut F>
    -    requires(__private::ConvertsToFunctionPointer)
    -  constexpr FnOnceRef(F&& object sus_lifetimebound) noexcept {
    -    storage_.object = ::sus::mem::addressof(object);
    -    invoke_ = &__private::Invoker<
    -        std::remove_reference_t>::template object_call_once;
    -  }
    -
    -  /// Construction from a capturing lambda or other callable object.
    -  ///
    -  /// #[doc.overloads=ctor.capturelambda]
    -  template <__private::CallableOnceMut F>
    -    requires(!__private::ConvertsToFunctionPointer)
    -  constexpr FnOnceRef(F&& object sus_lifetimebound) noexcept {
    -    storage_.object = ::sus::mem::addressof(object);
    -    invoke_ = &__private::Invoker<
    -        std::remove_reference_t>::template object_call_once;
    -  }
    -
    -  /// Construction from FnMutRef.
    -  ///
    -  /// Since FnMutRef is callable, FnOnceRef is already constructible from it,
    -  /// but this constructor avoids extra indirections being inserted when
    -  /// converting, since otherwise an extra invoker call would be introduced.
    -  ///
    -  /// #[doc.overloads=ctor.fnmutref]
    -  constexpr FnOnceRef(FnMutRef&& o sus_lifetimebound) noexcept
    -      : storage_(o.storage_), invoke_(::sus::mem::replace(o.invoke_, nullptr)) {
    -    ::sus::check(invoke_);  // Catch use-after-move.
    -  }
    -
    -  /// Construction from FnRef.
    -  ///
    -  /// Since FnRef is callable, FnOnceRef is already constructible from it, but
    -  /// this constructor avoids extra indirections being inserted when converting,
    -  /// since otherwise an extra invoker call would be introduced.
    -  ///
    -  /// #[doc.overloads=ctor.fnref]
    -  constexpr FnOnceRef(FnRef&& o sus_lifetimebound) noexcept
    -      : storage_(o.storage_), invoke_(::sus::mem::replace(o.invoke_, nullptr)) {
    -    ::sus::check(invoke_);  // Catch use-after-move.
    -  }
    -
    -  ~FnOnceRef() noexcept = default;
    -
    -  constexpr FnOnceRef(FnOnceRef&& o) noexcept
    -      : storage_(o.storage_), invoke_(::sus::mem::replace(o.invoke_, nullptr)) {
    -    ::sus::check(invoke_);  // Catch use-after-move.
    -  }
    -  constexpr FnOnceRef& operator=(FnOnceRef&& o) noexcept {
    -    storage_ = o.storage_;
    -    invoke_ = ::sus::mem::replace(o.invoke_, nullptr);
    -    ::sus::check(invoke_);  // Catch use-after-move.
    -    return *this;
    -  }
    -
    -  // Not copyable.
    -  FnOnceRef(const FnOnceRef&) noexcept = delete;
    -  FnOnceRef& operator=(const FnOnceRef&) noexcept = delete;
    -
    -  /// A split FnOnceRef object, which can be used to construct other FnOnceRef
    -  /// objects, but enforces that only one of them is called.
    -  ///
    -  /// The Split object must not outlive the FnOnceRef it's constructed from or
    -  /// Undefined Behaviour results.
    -  class Split {
    -   public:
    -    Split(FnOnceRef& fn sus_lifetimebound) : fn_(fn) {}
    -
    -    // Not Copy or Move, only used to construct FnOnceRef objects, which are
    -    // constructible from this type.
    -    Split(Split&&) = delete;
    -    Split& operator=(Split&&) = delete;
    -
    -    /// Runs the underlying `FnOnceRef`. The `FnOnceRef` may only be called a
    -    /// single time and will panic on the second call.
    -    R operator()(CallArgs... args) && {
    -      return ::sus::move(fn_)(::sus::forward(args)...);
    -    }
    -
    -   private:
    -    FnOnceRef& fn_;
    -  };
    -
    -  /// A `FnOnceRef` can be split into any number of `FnOnceRef` objects, while
    -  /// enforcing that the underlying function is only called a single time.
    -  ///
    -  /// This method returns a type that can convert into any number of `FnOnceRef`
    -  /// objects. If two of them are called, the second call will panic.
    -  ///
    -  /// The returned object must not outlive the `FnOnceRef` object it is
    -  /// constructed from, this is normally enforced by only using the `FnOnceRef`
    -  /// type in function parameters, which ensures it lives for the entire
    -  /// function body, and calling `split()` to construct temporary objects for
    -  /// passing to other functions that receive a `FnOnceRef`. The result of
    -  /// `split()` should never be stored as a member of an object.
    -  ///
    -  /// Only callable on an lvalue FnOnceRef (typically written as a function
    -  /// parameter) as an rvalue can be simply passed along without splitting.
    -  constexpr Split split() & noexcept sus_lifetimebound { return Split(*this); }
    -
    -  /// Runs and consumes the closure.
    -  inline R operator()(CallArgs... args) && {
    -    ::sus::check(invoke_);  // Catch use-after-move.
    -    return (*::sus::mem::replace(invoke_, nullptr))(
    -        storage_, ::sus::forward(args)...);
    -  }
    -
    -  /// `sus::construct::From` trait implementation.
    -  ///
    -  /// FnOnceRef satisfies `From` for the same types that it is constructible
    -  /// from: function pointers that exactly match its own signature, and callable
    -  /// objects (lambdas) that are compatible with its signature.
    -  template 
    -    requires(std::constructible_from)
    -  constexpr static auto from(F&& object sus_lifetimebound) noexcept {
    -    return FnOnceRef(::sus::forward(object));
    -  }
    -
    - private:
    -  friend FnMutRef;
    -  friend FnRef;
    -
    -  constexpr FnOnceRef(union __private::Storage storage,
    -                      __private::InvokeFnPtr invoke)
    -      : storage_(storage), invoke_(invoke) {}
    -
    -  union __private::Storage storage_;
    -  /// The `invoke_` pointer is set to null to indicate the FnOnceRef is
    -  /// moved-from. It uses another pointer value as its never-value.
    -  __private::InvokeFnPtr invoke_;
    -
    -  // A function pointer to use as a never-value for InvokeFnPointer.
    -  static R invoke_never_value(const union __private::Storage&, CallArgs...) {
    -    sus::unreachable();
    -  }
    -
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn,
    -                                  decltype(storage_.fnptr),
    -                                  decltype(storage_.object), decltype(invoke_));
    -  sus_class_never_value_field(::sus::marker::unsafe_fn, FnOnceRef, invoke_,
    -                              &invoke_never_value, &invoke_never_value);
    -  // For the NeverValueField.
    -  explicit constexpr FnOnceRef(::sus::mem::NeverValueConstructor) noexcept
    -      : invoke_(&invoke_never_value) {}
    -};
    -
    -}  // namespace sus::fn
    diff --git a/sus/fn/fn_ref_unittest.cc b/sus/fn/fn_ref_unittest.cc
    deleted file mode 100644
    index f25b2f38f..000000000
    --- a/sus/fn/fn_ref_unittest.cc
    +++ /dev/null
    @@ -1,891 +0,0 @@
    -// Copyright 2022 Google LLC
    -//
    -// Licensed under the Apache License, Version 2.0 (the "License");
    -// you may not use this file except in compliance with the License.
    -// You may obtain a copy of the License at
    -//
    -//     https://www.apache.org/licenses/LICENSE-2.0
    -//
    -// Unless required by applicable law or agreed to in writing, software
    -// distributed under the License is distributed on an "AS IS" BASIS,
    -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    -// See the License for the specific language governing permissions and
    -// limitations under the License.
    -
    -#include 
    -
    -#include "googletest/include/gtest/gtest.h"
    -#include "sus/construct/into.h"
    -#include "sus/fn/fn.h"
    -#include "sus/mem/forward.h"
    -#include "sus/mem/move.h"
    -#include "sus/mem/never_value.h"
    -#include "sus/mem/relocate.h"
    -#include "sus/mem/replace.h"
    -#include "sus/option/option.h"
    -#include "sus/prelude.h"
    -
    -namespace {
    -
    -using sus::construct::Into;
    -using sus::fn::FnMutRef;
    -using sus::fn::FnOnceRef;
    -using sus::fn::FnRef;
    -
    -static_assert(sus::mem::NeverValueField>);
    -static_assert(sus::mem::NeverValueField>);
    -static_assert(sus::mem::NeverValueField>);
    -static_assert(sus::mem::relocate_by_memcpy>);
    -static_assert(sus::mem::relocate_by_memcpy>);
    -static_assert(sus::mem::relocate_by_memcpy>);
    -
    -struct Copyable {
    -  Copyable(int i) : i(i) {}
    -  Copyable(const Copyable& c) = default;
    -  Copyable& operator=(const Copyable& c) = default;
    -  ~Copyable() { i = -10000000; }
    -
    -  int i = 0;
    -};
    -
    -struct MoveOnly {
    -  MoveOnly(int i) : i(i) {}
    -  MoveOnly(const MoveOnly& c) = delete;
    -  MoveOnly& operator=(const MoveOnly& c) = delete;
    -  MoveOnly(MoveOnly&& c) : i(::sus::mem::replace(c.i, -1)) {}
    -  MoveOnly& operator=(MoveOnly&& c) {
    -    i = ::sus::mem::replace(c.i, -1);
    -    return *this;
    -  }
    -  ~MoveOnly() { i = -10000000; }
    -
    -  int i = 0;
    -};
    -
    -// clang-format-off
    -
    -struct BaseClass {};
    -struct SubClass : public BaseClass {};
    -
    -static_assert(sizeof(FnOnceRef) == 2 * sizeof(void (*)()));
    -
    -void v_v_function() {}
    -int i_f_function(float) { return 0; }
    -void v_f_function(float) {}
    -BaseClass* b_b_function(BaseClass* b) { return b; }
    -SubClass* s_b_function(BaseClass* b) { return static_cast(b); }
    -SubClass* s_s_function(SubClass* b) { return b; }
    -
    -auto b_b_lambda = [a = 1](BaseClass* b) -> BaseClass* { return b; };
    -auto s_b_lambda = [a = 1](BaseClass* b) -> SubClass* {
    -  return static_cast(b);
    -};
    -auto s_s_lambda = [a = 1](SubClass* b) -> SubClass* { return b; };
    -
    -// FnRef types all have a never-value field.
    -static_assert(sus::mem::NeverValueField>);
    -static_assert(sus::mem::NeverValueField>);
    -static_assert(sus::mem::NeverValueField>);
    -//  Which allows them to not require a flag in Option.
    -static_assert(sizeof(sus::Option>) ==
    -              sizeof(FnOnceRef));
    -
    -// Closures are not copyable.
    -static_assert(!std::is_copy_constructible_v>);
    -static_assert(!std::is_copy_assignable_v>);
    -static_assert(!std::is_copy_constructible_v>);
    -static_assert(!std::is_copy_assignable_v>);
    -static_assert(!std::is_copy_constructible_v>);
    -static_assert(!std::is_copy_assignable_v>);
    -// Closures can be moved.
    -static_assert(std::is_move_constructible_v>);
    -static_assert(std::is_move_assignable_v>);
    -static_assert(std::is_move_constructible_v>);
    -static_assert(std::is_move_assignable_v>);
    -static_assert(std::is_move_constructible_v>);
    -static_assert(std::is_move_assignable_v>);
    -
    -// FnMutRef and FnRef are Clone, but not FnOnceRef. None of them are Copy.
    -static_assert(sus::mem::Move>);
    -static_assert(sus::mem::Move>);
    -static_assert(sus::mem::Move>);
    -static_assert(!sus::mem::Copy>);
    -static_assert(!sus::mem::Copy>);
    -static_assert(!sus::mem::Copy>);
    -static_assert(!sus::mem::Clone>);
    -static_assert(sus::mem::Clone>);
    -static_assert(sus::mem::Clone>);
    -
    -// Closures are trivially relocatable.
    -static_assert(sus::mem::relocate_by_memcpy>);
    -static_assert(sus::mem::relocate_by_memcpy>);
    -static_assert(sus::mem::relocate_by_memcpy>);
    -
    -// clang-format off
    -
    -// A function pointer, or convertible lambda, can be bound to FnOnceRef, FnMutRef and
    -// FnRef.
    -static_assert(std::is_constructible_v, decltype([]() {})>);
    -static_assert(std::is_constructible_v, decltype([]() {})>);
    -static_assert(std::is_constructible_v, decltype([]() {})>);
    -static_assert(std::is_constructible_v, decltype(v_v_function)>);
    -static_assert(std::is_constructible_v, decltype(v_v_function)>);
    -static_assert(std::is_constructible_v, decltype(v_v_function)>);
    -//  Non-void types for the same.
    -static_assert(std::is_constructible_v<
    -    FnOnceRef, decltype([](float) { return 1; })>
    -);
    -static_assert(std::is_constructible_v<
    -    FnMutRef, decltype([](float) { return 1; })>
    -);
    -static_assert(std::is_constructible_v<
    -    FnRef, decltype([](float) { return 1; })>
    -);
    -static_assert(std::is_constructible_v<
    -    FnOnceRef, decltype(i_f_function)>
    -);
    -static_assert(std::is_constructible_v<
    -    FnMutRef, decltype(i_f_function)>
    -);
    -static_assert(std::is_constructible_v<
    -    FnRef, decltype(i_f_function)>
    -);
    -// Lambdas with bound args can be bound to FnOnceRef, FnMutRef and FnRef.
    -static_assert(std::is_constructible_v<
    -    FnOnceRef, decltype([i = int(1)]() { (void)i; })>
    -);
    -static_assert(std::is_constructible_v<
    -    FnOnceRef, decltype([i = int(1)]() mutable { ++i; })>
    -);
    -static_assert(std::is_constructible_v<
    -    FnMutRef, decltype([i = int(1)]() { (void)i; })>
    -);
    -static_assert(std::is_constructible_v<
    -    FnMutRef, decltype([i = int(1)]() mutable { ++i; })>
    -);
    -static_assert(std::is_constructible_v<
    -    FnRef, decltype([i = int(1)]() { (void)i; })>
    -);
    -// But FnRef, which is const, can't hold a mutable lambda.
    -static_assert(!std::is_constructible_v<
    -    FnRef, decltype([i = int(1)]() mutable { ++i; })>
    -);
    -
    -// The return type of the FnOnceRef must match that of the lambda. It will not
    -// allow converting to void.
    -static_assert(std::is_constructible_v<
    -    FnOnceRef, decltype(s_b_function)>
    -);
    -static_assert(!std::is_constructible_v<
    -    FnOnceRef, decltype(b_b_function)>
    -);
    -static_assert(!std::is_constructible_v<
    -    FnOnceRef, decltype(b_b_function)>
    -);
    -static_assert(std::is_constructible_v<
    -    FnOnceRef, decltype(s_b_lambda)>
    -);
    -static_assert(!std::is_constructible_v<
    -    FnOnceRef, decltype(b_b_lambda)>
    -);
    -static_assert(!std::is_constructible_v<
    -    FnOnceRef, decltype(b_b_lambda)>
    -);
    -// Similarly, argument types can't be converted to a different type.
    -static_assert(std::is_constructible_v<
    -    FnOnceRef, decltype(s_s_function)>
    -);
    -static_assert(!std::is_constructible_v<
    -    FnOnceRef, decltype(s_s_function)>
    -);
    -static_assert(std::is_constructible_v<
    -    FnOnceRef, decltype(s_s_lambda)>
    -);
    -static_assert(!std::is_constructible_v<
    -    FnOnceRef, decltype(s_s_lambda)>
    -);
    -// But FnOnceRef type is compatible with convertible return and argument types in
    -// opposite directions.
    -// - If the return type Y of a lambda is convertible _to_ X, then FnOnceRef
    -// can be
    -//   used to store it.
    -// - If the argument type Y of a lambda is convertible _from_ X, then
    -// FnOnceRef<(X)>
    -//   can be used to store it.
    -//
    -// In both cases, the FnOnceRef is more strict than the lambda, guaranteeing that
    -// the lambda's requirements are met.
    -static_assert(std::is_constructible_v<
    -    FnOnceRef, decltype(s_b_lambda)>
    -);
    -static_assert(std::is_constructible_v<
    -    FnOnceRef, decltype(s_b_lambda)>
    -);
    -static_assert(std::is_constructible_v<
    -    FnOnceRef, decltype(s_b_function)>
    -);
    -static_assert(std::is_constructible_v<
    -    FnOnceRef, decltype(s_b_function)>
    -);
    -
    -// clang-format on
    -
    -template 
    -concept can_run =
    -    requires(Arg&& arg, FnOnceRef fnonce, FnMutRef FnMutRef
    -             //,
    -             //  FnRef FnRef
    -    ) {
    -      { sus::move(fnonce)(sus::forward(arg)) };
    -      { FnMutRef(sus::forward(arg)) };
    -      //{ sus::move(FnRef)(sus::forward(arg)) };
    -    };
    -// clang-format on
    -
    -// Int is copyable, so references are copied when passed.
    -static_assert(can_run);
    -static_assert(can_run);
    -static_assert(can_run);
    -static_assert(can_run);
    -static_assert(can_run);
    -static_assert(can_run);
    -// But for a move-only type, it can only be passed along as a reference or an
    -// rvalue.
    -static_assert(can_run);
    -static_assert(can_run);
    -static_assert(!can_run);
    -static_assert(!can_run);
    -static_assert(!can_run);
    -static_assert(!can_run);
    -static_assert(can_run);
    -static_assert(can_run);
    -static_assert(can_run);
    -static_assert(!can_run);
    -
    -// Receiving a mutable reference means it must be passed as a mutable reference.
    -static_assert(can_run);
    -static_assert(!can_run);
    -static_assert(!can_run);
    -
    -// Receiving a const reference means it must be passed as a reference.
    -static_assert(can_run);
    -static_assert(can_run);
    -static_assert(!can_run);
    -static_assert(!can_run);
    -static_assert(!can_run);
    -static_assert(!can_run);
    -
    -TEST(FnRef, Pointer) {
    -  {
    -    auto receive_fn = [](FnOnceRef f, i32 a, i32 b) {
    -      return sus::move(f)(a, b);
    -    };
    -    auto* ptr = +[](i32 a, i32 b) { return a * 2 + b; };
    -    EXPECT_EQ(receive_fn(ptr, 1, 2), 4);
    -  }
    -  {
    -    auto receive_fn = [](FnMutRef f, i32 a, i32 b) {
    -      f(a, b);
    -      return sus::move(f)(a, b);
    -    };
    -    auto* ptr = +[](i32 a, i32 b) { return a * 2 + b; };
    -    EXPECT_EQ(receive_fn(ptr, 1, 2), 4);
    -  }
    -  {
    -    {
    -      auto receive_fn = [](FnRef f, i32 a, i32 b) {
    -        f(a, b);
    -        return sus::move(f)(a, b);
    -      };
    -      auto* ptr = +[](i32 a, i32 b) { return a * 2 + b; };
    -      EXPECT_EQ(receive_fn(ptr, 1, 2), 4);
    -    }
    -  }
    -}
    -
    -TEST(FnRef, CapturelessLambda) {
    -  {
    -    auto receive_fn = [](FnOnceRef f, i32 a, i32 b) {
    -      return sus::move(f)(a, b);
    -    };
    -    auto lambda = [](i32 a, i32 b) { return a * 2 + b; };
    -    EXPECT_EQ(receive_fn(lambda, 1, 2), 4);
    -  }
    -  {
    -    auto receive_fn = [](FnMutRef f, i32 a, i32 b) {
    -      f(a, b);
    -      return sus::move(f)(a, b);
    -    };
    -    auto lambda = [i = 1_i32](i32 a, i32 b) mutable {
    -      i += 1;
    -      return a * 2 + b;
    -    };
    -    EXPECT_EQ(receive_fn(lambda, 1, 2), 4);
    -  }
    -  {
    -    {
    -      auto receive_fn = [](FnRef f, i32 a, i32 b) {
    -        f(a, b);
    -        return sus::move(f)(a, b);
    -      };
    -      auto lambda = [](i32 a, i32 b) { return a * 2 + b; };
    -      EXPECT_EQ(receive_fn(lambda, 1, 2), 4);
    -    }
    -  }
    -}
    -
    -TEST(FnRef, Lambda) {
    -  {
    -    auto receive_fn = [](FnOnceRef f, i32 b) {
    -      return sus::move(f)(b);
    -    };
    -    auto lambda = [a = 1_i32](i32 b) { return a * 2 + b; };
    -    EXPECT_EQ(receive_fn(lambda, 2), 4);
    -  }
    -  {
    -    auto receive_fn = [](FnMutRef f, i32 b) {
    -      f(b);
    -      return sus::move(f)(b);
    -    };
    -    auto lambda = [a = 1_i32](i32 b) mutable {
    -      a += 1;
    -      return a * 2 + b;
    -    };
    -    EXPECT_EQ(receive_fn(lambda, 2), 8);
    -  }
    -  {
    -    auto receive_fn = [](FnRef f, i32 b) {
    -      f(b);
    -      return sus::move(f)(b);
    -    };
    -    auto lambda = [a = 1_i32](i32 b) { return a * 2 + b; };
    -    EXPECT_EQ(receive_fn(lambda, 2), 4);
    -  }
    -}
    -
    -TEST(FnRef, TemplateLambda) {
    -  {
    -    auto receive_fn = [](FnOnceRef f, i32 b) {
    -      return sus::move(f)(b);
    -    };
    -    auto lambda = [a = 1_i32](auto b) { return a * 2 + b; };
    -    EXPECT_EQ(receive_fn(lambda, 2), 4);
    -  }
    -  {
    -    auto receive_fn = [](FnMutRef f, i32 b) {
    -      f(b);
    -      return sus::move(f)(b);
    -    };
    -    auto lambda = [a = 1_i32](auto b) mutable {
    -      a += 1;
    -      return a * 2 + b;
    -    };
    -    EXPECT_EQ(receive_fn(lambda, 2), 8);
    -  }
    -  {
    -    auto receive_fn = [](FnRef f, i32 b) {
    -      f(b);
    -      return sus::move(f)(b);
    -    };
    -    auto lambda = [a = 1_i32](auto b) { return a * 2 + b; };
    -    EXPECT_EQ(receive_fn(lambda, 2), 4);
    -  }
    -}
    -
    -TEST(FnDeathTest, NullPointer) {
    -  void (*f)() = nullptr;
    -#if GTEST_HAS_DEATH_TEST
    -  EXPECT_DEATH((FnOnceRef(f)), "");
    -#endif
    -#if GTEST_HAS_DEATH_TEST
    -  EXPECT_DEATH((FnMutRef(f)), "");
    -#endif
    -#if GTEST_HAS_DEATH_TEST
    -  EXPECT_DEATH((FnRef(f)), "");
    -#endif
    -}
    -
    -TEST(FnDeathTest, CallAfterMoveConstruct) {
    -  {
    -    [](FnOnceRef x) {
    -      [](auto) {}(sus::move(x));
    -#if GTEST_HAS_DEATH_TEST
    -      EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -    }([]() {});
    -  }
    -  {
    -    [](FnMutRef x) {
    -      [](auto) {}(sus::move(x));
    -#if GTEST_HAS_DEATH_TEST
    -      EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -    }([]() {});
    -  }
    -  {
    -    [](FnRef x) {
    -      [](auto) {}(sus::move(x));
    -#if GTEST_HAS_DEATH_TEST
    -      EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -    }([]() {});
    -  }
    -}
    -
    -TEST(FnDeathTest, CallAfterMoveAssign) {
    -  {
    -    [](FnOnceRef x, FnOnceRef y) {
    -      y = sus::move(x);
    -#if GTEST_HAS_DEATH_TEST
    -      EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -    }([]() {}, []() {});
    -  }
    -  {
    -    [](FnMutRef x, FnMutRef y) {
    -      y = sus::move(x);
    -#if GTEST_HAS_DEATH_TEST
    -      EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -    }([]() {}, []() {});
    -  }
    -  {
    -    [](FnRef x, FnRef y) {
    -      y = sus::move(x);
    -#if GTEST_HAS_DEATH_TEST
    -      EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -    }([]() {}, []() {});
    -  }
    -}
    -
    -TEST(FnDeathTest, CallAfterCall) {
    -  {
    -    [](FnOnceRef x) {
    -      sus::move(x)();
    -#if GTEST_HAS_DEATH_TEST
    -      EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -    }([]() {});
    -  }
    -  {
    -    [](FnMutRef x) {
    -      sus::move(x)();
    -#if GTEST_HAS_DEATH_TEST
    -      EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -    }([]() {});
    -  }
    -  {
    -    [](FnRef x) {
    -      sus::move(x)();
    -#if GTEST_HAS_DEATH_TEST
    -      EXPECT_DEATH(sus::move(x)(), "");
    -#endif
    -    }([]() {});
    -  }
    -}
    -
    -TEST(FnMutRef, ConvertToFnOnce) {
    -  auto receive_fnonce = [](FnOnceRef x) { return sus::move(x)(); };
    -  auto receive_fnmut = [&](FnMutRef x) {
    -    return receive_fnonce(sus::move(x));
    -  };
    -  EXPECT_EQ(receive_fnmut([]() { return 2_i32; }), 2);
    -}
    -
    -TEST(FnRef, ConvertToFnOnce) {
    -  auto receive_fnonce = [](FnOnceRef x) { return sus::move(x)(); };
    -  auto receive_fn = [&](FnRef x) {
    -    return receive_fnonce(sus::move(x));
    -  };
    -  EXPECT_EQ(receive_fn([]() { return 2_i32; }), 2);
    -}
    -
    -TEST(FnRef, ConvertToFnMut) {
    -  auto receive_fnmut = [](FnMutRef x) { return sus::move(x)(); };
    -  auto receive_fn = [&](FnRef x) { return receive_fnmut(sus::move(x)); };
    -  EXPECT_EQ(receive_fn([]() { return 2_i32; }), 2);
    -}
    -
    -TEST(FnRef, ConstructionFromConstMut) {
    -  struct Captureless {
    -    i32 operator()() const { return 2; }
    -  };
    -  struct Capture {
    -    i32 operator()() const { return i; }
    -    i32 i = 2;
    -  };
    -
    -  // Const callable can be put in all the FnRef types.
    -  static_assert(sus::fn::__private::CallableMut);
    -  EXPECT_EQ(2,
    -            [](FnOnceRef m) { return sus::move(m)(); }(Captureless()));
    -  EXPECT_EQ(2, [](FnMutRef m) { return sus::move(m)(); }(Captureless()));
    -  EXPECT_EQ(2, [](FnRef m) { return sus::move(m)(); }(Captureless()));
    -  static_assert(sus::fn::__private::CallableMut);
    -  EXPECT_EQ(2, [](FnOnceRef m) { return sus::move(m)(); }(Capture()));
    -  EXPECT_EQ(2, [](FnMutRef m) { return sus::move(m)(); }(Capture()));
    -  EXPECT_EQ(2, [](FnRef m) { return sus::move(m)(); }(Capture()));
    -
    -  struct CapturelessMut {
    -    i32 operator()() { return 2; }
    -  };
    -  struct CaptureMut {
    -    i32 operator()() { return i; }
    -    i32 i = 2;
    -  };
    -
    -  // Mutable callable can only be put in the mutable FnRef types.
    -  static_assert(sus::fn::__private::CallableMut);
    -  static_assert(std::is_constructible_v, CapturelessMut&&>);
    -  static_assert(std::is_constructible_v, CapturelessMut&&>);
    -  static_assert(!std::is_constructible_v, CapturelessMut&&>);
    -  EXPECT_EQ(
    -      2, [](FnOnceRef m) { return sus::move(m)(); }(CapturelessMut()));
    -  EXPECT_EQ(2,
    -            [](FnMutRef m) { return sus::move(m)(); }(CapturelessMut()));
    -
    -  static_assert(sus::fn::__private::CallableMut);
    -  static_assert(std::is_constructible_v, CaptureMut&&>);
    -  static_assert(std::is_constructible_v, CaptureMut&&>);
    -  static_assert(!std::is_constructible_v, CaptureMut&&>);
    -  EXPECT_EQ(2, [](FnOnceRef m) { return sus::move(m)(); }(CaptureMut()));
    -  EXPECT_EQ(2, [](FnMutRef m) { return sus::move(m)(); }(CaptureMut()));
    -}
    -
    -TEST(FnRef, IntoFromConstMut) {
    -  i32 (*f)() = +[]() { return 2_i32; };
    -
    -  // Function pointer can be put in all the FnRef types.
    -  static_assert(sus::construct::Into>);
    -  static_assert(sus::construct::Into>);
    -  static_assert(sus::construct::Into>);
    -  EXPECT_EQ(2, FnOnceRef::from(f)());
    -  EXPECT_EQ(2, FnMutRef::from(f)());
    -  EXPECT_EQ(2, FnRef::from(f)());
    -
    -  struct Captureless {
    -    i32 operator()() const { return 2; }
    -  };
    -  struct Capture {
    -    i32 operator()() const { return i; }
    -    i32 i = 2;
    -  };
    -
    -  // Const callable can be put in all the FnRef types.
    -  static_assert(sus::construct::Into>);
    -  static_assert(sus::construct::Into>);
    -  static_assert(sus::construct::Into>);
    -  EXPECT_EQ(2, FnOnceRef::from(Captureless())());
    -  EXPECT_EQ(2, FnMutRef::from(Captureless())());
    -  EXPECT_EQ(2, FnRef::from(Captureless())());
    -  static_assert(sus::construct::Into>);
    -  static_assert(sus::construct::Into>);
    -  static_assert(sus::construct::Into>);
    -  EXPECT_EQ(2, FnOnceRef::from(Capture())());
    -  EXPECT_EQ(2, FnMutRef::from(Capture())());
    -  EXPECT_EQ(2, FnRef::from(Capture())());
    -
    -  struct CapturelessMut {
    -    i32 operator()() { return 2; }
    -  };
    -  struct CaptureMut {
    -    i32 operator()() { return i; }
    -    i32 i = 2;
    -  };
    -
    -  // Mutable callable can only be put in the mutable FnRef types.
    -  static_assert(sus::construct::Into>);
    -  static_assert(sus::construct::Into>);
    -  static_assert(!sus::construct::Into>);
    -  EXPECT_EQ(2, FnOnceRef::from(CapturelessMut())());
    -  EXPECT_EQ(2, FnMutRef::from(CapturelessMut())());
    -
    -  static_assert(sus::construct::Into>);
    -  static_assert(sus::construct::Into>);
    -  static_assert(!sus::construct::Into>);
    -  EXPECT_EQ(2, FnOnceRef::from(CaptureMut())());
    -  EXPECT_EQ(2, FnMutRef::from(CaptureMut())());
    -}
    -
    -TEST(FnRef, CallsCorrectOverload) {
    -  static i32 const_calls;
    -  static i32 mut_calls;
    -  struct S {
    -    void operator()() const { const_calls += 1; }
    -    void operator()() { mut_calls += 1; }
    -  };
    -
    -  [](FnOnceRef m) { sus::move(m)(); }(S());
    -  EXPECT_EQ(const_calls, 0);
    -  EXPECT_EQ(mut_calls, 1);
    -
    -  [](FnMutRef m) { m(); }(S());
    -  EXPECT_EQ(const_calls, 0);
    -  EXPECT_EQ(mut_calls, 2);
    -
    -  [](FnRef m) { m(); }(S());
    -  EXPECT_EQ(const_calls, 1);
    -  EXPECT_EQ(mut_calls, 2);
    -
    -  // The FnRef is converted to FnMutRef but still calls the const overload.
    -  [](FnRef m) { [](FnMutRef m) { m(); }(sus::move(m)); }(S());
    -  EXPECT_EQ(const_calls, 2);
    -  EXPECT_EQ(mut_calls, 2);
    -
    -  // The FnRef is converted to FnOnceRef but still calls the const overload.
    -  [](FnRef m) {
    -    [](FnOnceRef m) { sus::move(m)(); }(sus::move(m));
    -  }(S());
    -  EXPECT_EQ(const_calls, 3);
    -  EXPECT_EQ(mut_calls, 2);
    -}
    -
    -TEST(FnRef, Clone) {
    -  static_assert(sus::mem::Clone>);
    -  auto clones_fn = [](FnRef f) {
    -    return [](FnOnceRef f1) { return sus::move(f1)(); }(f.clone()) +
    -           [](FnOnceRef f2) { return sus::move(f2)(); }(f.clone());
    -  };
    -  EXPECT_EQ(4, clones_fn([]() { return 2_i32; }));
    -
    -  static_assert(sus::mem::Clone>);
    -  auto clones_fnmut = [](FnMutRef f) {
    -    return [](FnOnceRef f1) { return sus::move(f1)(); }(f.clone()) +
    -           [](FnOnceRef f2) { return sus::move(f2)(); }(f.clone());
    -  };
    -  EXPECT_EQ(5, clones_fnmut([i = 1_i32]() mutable {
    -              i += 1;
    -              return i;
    -            }));
    -
    -  static_assert(!sus::mem::Clone>);
    -}
    -
    -TEST(FnOnceRef, Split) {
    -  // The return type of split() is not Copy or Move
    -  static_assert(
    -      !::sus::mem::Copy&>().split())>);
    -  static_assert(
    -      !::sus::mem::Move&>().split())>);
    -  // It's only used to build more FnOnceRef objects.
    -  static_assert(::sus::construct::Into<
    -                decltype(std::declval&>().split()),
    -                FnOnceRef>);
    -  // And not FnMutRef or FnRef, as that loses the intention to only call it
    -  // once. This is implemented by making the operator() callable as an rvalue
    -  // only.
    -  static_assert(!::sus::construct::Into<
    -                decltype(std::declval&>().split()),
    -                FnMutRef>);
    -  static_assert(
    -      !::sus::construct::Into<
    -          decltype(std::declval&>().split()), FnRef>);
    -
    -  // split() as rvalues. First split is run.
    -  auto rsplits_fnonce = [](FnOnceRef f) {
    -    i32 a = [](FnOnceRef f) { return sus::move(f)(); }(f.split());
    -    i32 b = [](FnOnceRef) {
    -      // Don't run the `FnOnceRef` as only one of the splits may run the
    -      // FnOnceRef.
    -      return 0_i32;
    -    }(f.split());
    -    return a + b;
    -  };
    -  EXPECT_EQ(2, rsplits_fnonce([i = 1_i32]() mutable {
    -              i += 1;
    -              return i;
    -            }));
    -
    -  // split() as rvalues. Second split is run.
    -  auto rsplits_fnonce2 = [](FnOnceRef f) {
    -    i32 a = [](FnOnceRef) {
    -      // Don't run the `FnOnceRef` as only one of the splits may run the
    -      // FnOnceRef.
    -      return 0_i32;
    -    }(f.split());
    -    i32 b = [](FnOnceRef f) { return sus::move(f)(); }(f.split());
    -    return a + b;
    -  };
    -  EXPECT_EQ(2, rsplits_fnonce([i = 1_i32]() mutable {
    -              i += 1;
    -              return i;
    -            }));
    -
    -  // split() as lvalues. First split is run.
    -  auto lsplits_fnonce = [](FnOnceRef f) {
    -    auto split = f.split();
    -    i32 a = [](FnOnceRef f) { return sus::move(f)(); }(f);
    -    i32 b = [](FnOnceRef) {
    -      // Don't run the `FnOnceRef` as only one of the splits may run the
    -      // FnOnceRef.
    -      return 0_i32;
    -    }(f);
    -    return a + b;
    -  };
    -  EXPECT_EQ(2, lsplits_fnonce([i = 1_i32]() mutable {
    -              i += 1;
    -              return i;
    -            }));
    -
    -  // split() as lvalues. Second split is run.
    -  auto lsplits_fnonce2 = [](FnOnceRef f) {
    -    auto split = f.split();
    -    i32 a = [](FnOnceRef) {
    -      // Don't run the `FnOnceRef` as only one of the splits may run the
    -      // FnOnceRef.
    -      return 0_i32;
    -    }(f);
    -    i32 b = [](FnOnceRef f) { return sus::move(f)(); }(f);
    -    return a + b;
    -  };
    -  EXPECT_EQ(2, lsplits_fnonce([i = 1_i32]() mutable {
    -              i += 1;
    -              return i;
    -            }));
    -}
    -
    -struct C {
    -  i32 method(i32 p) const& { return p + 1; }
    -  i32 method(i32 p) & { return p + 2; }
    -  i32 method(i32 p) && { return p + 3; }
    -
    -  i32 simple() const { return 99; }
    -};
    -
    -TEST(FnOnceRef, Methods) {
    -  {
    -    auto test_simple = [](FnOnceRef y) {
    -      const C c;
    -      return call_once(sus::move(y), c);
    -    };
    -    EXPECT_EQ(test_simple(&C::simple), 99);
    -  }
    -  {
    -    auto test_simple = [](FnOnceRef y) {
    -      C c;
    -      return call_once(sus::move(y), c);
    -    };
    -    EXPECT_EQ(test_simple(&C::simple), 99);
    -  }
    -  {
    -    auto test_simple = [](FnOnceRef y) {
    -      return call_once(sus::move(y), C());
    -    };
    -    EXPECT_EQ(test_simple(&C::simple), 99);
    -  }
    -
    -  // Overloaded methods.
    -  {
    -    auto test_const = [](FnOnceRef y) {
    -      return call_once(sus::move(y), C(), 10_i32);
    -    };
    -    EXPECT_EQ(  //
    -        test_const(static_cast(&C::method)), 10 + 1);
    -
    -    auto test_mut = [](FnOnceRef y) {
    -      C c;
    -      return call_once(sus::move(y), c, 10_i32);
    -    };
    -    EXPECT_EQ(  //
    -        test_mut(static_cast(&C::method)), 10 + 2);
    -
    -    auto test_rvalue = [](FnOnceRef y) {
    -      C c;
    -      return call_once(sus::move(y), sus::move(c), 10_i32);
    -    };
    -    EXPECT_EQ(  //
    -        test_rvalue(static_cast(&C::method)), 10 + 3);
    -  }
    -}
    -
    -TEST(FnMutRef, Methods) {
    -  {
    -    auto test_simple = [](FnMutRef y) {
    -      const C c;
    -      return call_mut(y, c);
    -    };
    -    EXPECT_EQ(test_simple(&C::simple), 99);
    -  }
    -  {
    -    auto test_simple = [](FnMutRef y) {
    -      C c;
    -      return call_mut(y, c);
    -    };
    -    EXPECT_EQ(test_simple(&C::simple), 99);
    -  }
    -  {
    -    auto test_simple = [](FnMutRef y) { return call_mut(y, C()); };
    -    EXPECT_EQ(test_simple(&C::simple), 99);
    -  }
    -
    -  // Overloaded methods.
    -  {
    -    auto test_const = [](FnMutRef y) {
    -      return call_mut(y, C(), 10_i32);
    -    };
    -    EXPECT_EQ(  //
    -        test_const(static_cast(&C::method)), 10 + 1);
    -
    -    auto test_mut = [](FnMutRef y) {
    -      C c;
    -      return call_mut(y, c, 10_i32);
    -    };
    -    EXPECT_EQ(  //
    -        test_mut(static_cast(&C::method)), 10 + 2);
    -
    -    auto test_rvalue = [](FnMutRef y) {
    -      C c;
    -      return call_mut(y, sus::move(c), 10_i32);
    -    };
    -    EXPECT_EQ(  //
    -        test_rvalue(static_cast(&C::method)), 10 + 3);
    -  }
    -}
    -
    -TEST(FnRef, Methods) {
    -  {
    -    auto test_simple = [](FnRef y) {
    -      const C c;
    -      return call(y, c);
    -    };
    -    EXPECT_EQ(test_simple(&C::simple), 99);
    -  }
    -  {
    -    auto test_simple = [](FnRef y) {
    -      C c;
    -      return call(y, c);
    -    };
    -    EXPECT_EQ(test_simple(&C::simple), 99);
    -  }
    -  {
    -    auto test_simple = [](FnRef y) { return call(y, C()); };
    -    EXPECT_EQ(test_simple(&C::simple), 99);
    -  }
    -
    -  // Overloaded methods.
    -  {
    -    auto test_const = [](FnRef y) {
    -      return call(y, C(), 10_i32);
    -    };
    -    EXPECT_EQ(  //
    -        test_const(static_cast(&C::method)), 10 + 1);
    -
    -    auto test_mut = [](FnRef y) {
    -      C c;
    -      return call(y, c, 10_i32);
    -    };
    -    EXPECT_EQ(  //
    -        test_mut(static_cast(&C::method)), 10 + 2);
    -
    -    auto test_rvalue = [](FnRef y) {
    -      C c;
    -      return call(y, sus::move(c), 10_i32);
    -    };
    -    EXPECT_EQ(  //
    -        test_rvalue(static_cast(&C::method)), 10 + 3);
    -  }
    -}
    -
    -}  // namespace
    diff --git a/sus/iter/__private/iter_compare.h b/sus/iter/__private/iter_compare.h
    index e466ff3c2..fd287d47c 100644
    --- a/sus/iter/__private/iter_compare.h
    +++ b/sus/iter/__private/iter_compare.h
    @@ -16,6 +16,7 @@
     
     #include "sus/fn/fn_concepts.h"
     #include "sus/iter/iterator_concept.h"
    +#include "sus/option/option.h"
     
     namespace sus::iter::__private {
     
    diff --git a/sus/iter/adaptors/filter.h b/sus/iter/adaptors/filter.h
    index 0c56dccb1..9a310157f 100644
    --- a/sus/iter/adaptors/filter.h
    +++ b/sus/iter/adaptors/filter.h
    @@ -16,7 +16,7 @@
     // IWYU pragma: friend "sus/.*"
     #pragma once
     
    -#include "sus/fn/fn_box_defn.h"
    +#include "sus/fn/fn_concepts.h"
     #include "sus/iter/iterator_defn.h"
     #include "sus/mem/move.h"
     #include "sus/mem/relocate.h"
    diff --git a/sus/iter/adaptors/filter_map.h b/sus/iter/adaptors/filter_map.h
    index e60d4310e..f92b800b2 100644
    --- a/sus/iter/adaptors/filter_map.h
    +++ b/sus/iter/adaptors/filter_map.h
    @@ -16,7 +16,7 @@
     // IWYU pragma: friend "sus/.*"
     #pragma once
     
    -#include "sus/fn/fn_box_defn.h"
    +#include "sus/fn/fn_concepts.h"
     #include "sus/iter/iterator_defn.h"
     #include "sus/mem/move.h"
     #include "sus/mem/relocate.h"
    diff --git a/sus/iter/adaptors/flat_map.h b/sus/iter/adaptors/flat_map.h
    index 55b5eae12..db25351fd 100644
    --- a/sus/iter/adaptors/flat_map.h
    +++ b/sus/iter/adaptors/flat_map.h
    @@ -16,7 +16,7 @@
     // IWYU pragma: friend "sus/.*"
     #pragma once
     
    -#include "sus/fn/fn_box_defn.h"
    +#include "sus/fn/fn_concepts.h"
     #include "sus/iter/iterator_defn.h"
     #include "sus/mem/move.h"
     #include "sus/mem/relocate.h"
    diff --git a/sus/iter/adaptors/fuse.h b/sus/iter/adaptors/fuse.h
    index 66e2f8c40..c74b88c97 100644
    --- a/sus/iter/adaptors/fuse.h
    +++ b/sus/iter/adaptors/fuse.h
    @@ -16,7 +16,7 @@
     // IWYU pragma: friend "sus/.*"
     #pragma once
     
    -#include "sus/fn/fn_box_defn.h"
    +#include "sus/fn/fn_concepts.h"
     #include "sus/iter/iterator_defn.h"
     #include "sus/mem/move.h"
     #include "sus/mem/relocate.h"
    diff --git a/sus/iter/adaptors/inspect.h b/sus/iter/adaptors/inspect.h
    index c6a04a953..f4be59ab2 100644
    --- a/sus/iter/adaptors/inspect.h
    +++ b/sus/iter/adaptors/inspect.h
    @@ -16,7 +16,7 @@
     // IWYU pragma: friend "sus/.*"
     #pragma once
     
    -#include "sus/fn/fn_box_defn.h"
    +#include "sus/fn/fn_concepts.h"
     #include "sus/iter/iterator_defn.h"
     #include "sus/mem/move.h"
     #include "sus/mem/relocate.h"
    diff --git a/sus/iter/adaptors/map.h b/sus/iter/adaptors/map.h
    index aad8b8be8..e297e78b6 100644
    --- a/sus/iter/adaptors/map.h
    +++ b/sus/iter/adaptors/map.h
    @@ -16,7 +16,7 @@
     // IWYU pragma: friend "sus/.*"
     #pragma once
     
    -#include "sus/fn/fn_box_defn.h"
    +#include "sus/fn/fn_concepts.h"
     #include "sus/iter/iterator_defn.h"
     #include "sus/mem/move.h"
     #include "sus/mem/relocate.h"
    diff --git a/sus/iter/adaptors/map_while.h b/sus/iter/adaptors/map_while.h
    index d175a0787..e3088d3d4 100644
    --- a/sus/iter/adaptors/map_while.h
    +++ b/sus/iter/adaptors/map_while.h
    @@ -16,7 +16,7 @@
     // IWYU pragma: friend "sus/.*"
     #pragma once
     
    -#include "sus/fn/fn_box_defn.h"
    +#include "sus/fn/fn_concepts.h"
     #include "sus/iter/iterator_defn.h"
     #include "sus/mem/move.h"
     #include "sus/mem/relocate.h"
    diff --git a/sus/iter/adaptors/peekable.h b/sus/iter/adaptors/peekable.h
    index 0b7270ed2..eb664c65f 100644
    --- a/sus/iter/adaptors/peekable.h
    +++ b/sus/iter/adaptors/peekable.h
    @@ -74,7 +74,7 @@ class [[nodiscard]] Peekable final
       /// If `func` returns `true` for the next value of this iterator, consume and
       /// return it. Otherwise, return `None`.
       constexpr Option next_if(
    -      ::sus::fn::FnOnceRef&)>
    +      ::sus::fn::FnOnce&)> auto
               pred) noexcept {
         Option o = next();
         if (o.is_some() && ::sus::fn::call_once(::sus::move(pred), o.as_value())) {
    diff --git a/sus/iter/adaptors/reverse.h b/sus/iter/adaptors/reverse.h
    index 30bc4256f..a21859c19 100644
    --- a/sus/iter/adaptors/reverse.h
    +++ b/sus/iter/adaptors/reverse.h
    @@ -16,7 +16,7 @@
     // IWYU pragma: friend "sus/.*"
     #pragma once
     
    -#include "sus/fn/fn_box_defn.h"
    +#include "sus/fn/fn_concepts.h"
     #include "sus/iter/iterator_concept.h"
     #include "sus/iter/iterator_defn.h"
     #include "sus/mem/move.h"
    diff --git a/sus/iter/adaptors/scan.h b/sus/iter/adaptors/scan.h
    index 2bf791ea3..5e1f4c717 100644
    --- a/sus/iter/adaptors/scan.h
    +++ b/sus/iter/adaptors/scan.h
    @@ -16,7 +16,7 @@
     // IWYU pragma: friend "sus/.*"
     #pragma once
     
    -#include "sus/fn/fn_box_defn.h"
    +#include "sus/fn/fn_concepts.h"
     #include "sus/iter/iterator_defn.h"
     #include "sus/mem/move.h"
     #include "sus/mem/relocate.h"
    diff --git a/sus/iter/adaptors/skip_while.h b/sus/iter/adaptors/skip_while.h
    index a8f660d6e..aea9dadf6 100644
    --- a/sus/iter/adaptors/skip_while.h
    +++ b/sus/iter/adaptors/skip_while.h
    @@ -16,7 +16,7 @@
     // IWYU pragma: friend "sus/.*"
     #pragma once
     
    -#include "sus/fn/fn_box_defn.h"
    +#include "sus/fn/fn_concepts.h"
     #include "sus/iter/iterator_defn.h"
     #include "sus/mem/move.h"
     #include "sus/mem/relocate.h"
    diff --git a/sus/iter/iterator_defn.h b/sus/iter/iterator_defn.h
    index 68350bd8b..5de27dec9 100644
    --- a/sus/iter/iterator_defn.h
    +++ b/sus/iter/iterator_defn.h
    @@ -1504,29 +1504,24 @@ template <
                !std::is_reference_v)
     constexpr Option IteratorBase::max_by_key(
         KeyFn fn) && noexcept {
    -  auto fold = [&fn](sus::Tuple&& acc, Item&& item) {
    -    Key key = ::sus::fn::call_mut(fn, item);
    -    if (key >= acc.template at<0>())
    -      return sus::Tuple(::sus::move(key),
    -                                   ::sus::forward(item));
    -    return ::sus::move(acc);
    +  // Builds a map function that turns an Item into a Tuple by using
    +  // `keyfn`.
    +  auto key = [](KeyFn keyfn) {
    +    return [keyfn](Item&& item) {
    +      return sus::Tuple(keyfn(item), sus::forward(item));
    +    };
       };
     
    -  // TODO: We could do .map() to make the tuple and use max_by(), and not need
    -  // the if statement but for that .map() would need to take a reference
    -  // on/ownership of `fn` and that requires heap allocations for FnMutBox.
    -  auto first = as_subclass_mut().next();
    -  if (first.is_none()) return Option();
    -  Key first_key = fn(first.as_value());
    -  return Option(
    -      // Run fold() over a Tuple to find the max Key.
    -      static_cast(*this)
    -          .fold(sus::Tuple(first_key,
    -                                      ::sus::move(first).unwrap_unchecked(
    -                                          ::sus::marker::unsafe_fn)),
    -                fold)
    -          // Pull out the Item for the max Key.
    -          .template into_inner<1>());
    +  // Compares just the keys.
    +  auto compare = [](const sus::Tuple& x,
    +                    const sus::Tuple& y) {
    +    return x.template at<0>() <=> y.template at<0>();
    +  };
    +
    +  return static_cast(*this).map(key(fn)).max_by(compare).map(
    +      [](auto&& key_item) -> Item {
    +        return sus::move(key_item).template into_inner<1>();
    +      });
     }
     
     template 
    @@ -1562,29 +1557,24 @@ template <
                !std::is_reference_v)
     constexpr Option IteratorBase::min_by_key(
         KeyFn fn) && noexcept {
    -  auto fold = [&fn](sus::Tuple&& acc, Item&& item) {
    -    Key key = ::sus::fn::call_mut(fn, item);
    -    if (key < acc.template at<0>())
    -      return sus::Tuple(::sus::move(key),
    -                                   ::sus::forward(item));
    -    return ::sus::move(acc);
    +  // Builds a map function that turns an Item into a Tuple by using
    +  // `keyfn`.
    +  auto key = [](KeyFn keyfn) {
    +    return [keyfn](Item&& item) {
    +      return sus::Tuple(keyfn(item), sus::forward(item));
    +    };
       };
     
    -  // TODO: We could do .map() to make the tuple and use min_by(), and not need
    -  // the if statement but for that .map() would need to take a reference
    -  // on/ownership of `fn` and that requires heap allocations for FnMutBox.
    -  auto first = as_subclass_mut().next();
    -  if (first.is_none()) return Option();
    -  Key first_key = fn(first.as_value());
    -  return Option(
    -      // Run fold() over a Tuple to find the min Key.
    -      static_cast(*this)
    -          .fold(sus::Tuple(first_key,
    -                                      ::sus::move(first).unwrap_unchecked(
    -                                          ::sus::marker::unsafe_fn)),
    -                fold)
    -          // Pull out the Item for the min Key.
    -          .template into_inner<1>());
    +  // Compares just the keys.
    +  auto compare = [](const sus::Tuple& x,
    +                    const sus::Tuple& y) {
    +    return x.template at<0>() <=> y.template at<0>();
    +  };
    +
    +  return static_cast(*this).map(key(fn)).min_by(compare).map(
    +      [](auto&& key_item) -> Item {
    +        return sus::move(key_item).template into_inner<1>();
    +      });
     }
     
     template 
    diff --git a/sus/iter/once_with.h b/sus/iter/once_with.h
    index 39b2f80a6..f92511e6c 100644
    --- a/sus/iter/once_with.h
    +++ b/sus/iter/once_with.h
    @@ -14,7 +14,7 @@
     
     #pragma once
     
    -#include "sus/fn/fn_box_defn.h"
    +#include "sus/fn/fn_concepts.h"
     #include "sus/iter/iterator_defn.h"
     #include "sus/mem/move.h"
     #include "sus/mem/relocate.h"
    @@ -23,7 +23,7 @@ namespace sus::iter {
     
     using ::sus::option::Option;
     
    -template 
    +template 
     class OnceWith;
     
     /// Creates an iterator that lazily generates a value exactly once by invoking
    @@ -41,45 +41,59 @@ class OnceWith;
     /// auto ow = sus::iter::once_with([]() { return 3_u16; });
     /// sus::check(ow.next().unwrap() == 3_u16);
     /// ```
    -template 
    -inline OnceWith once_with(::sus::fn::FnMutBox gen) noexcept {
    -  return OnceWith(::sus::move(gen));
    +template  GenFn>
    +constexpr inline OnceWith once_with(GenFn gen) noexcept {
    +  return OnceWith(::sus::move(gen));
     }
     
     /// An Iterator that walks over at most a single Item.
    -template 
    -class [[nodiscard]] [[sus_trivial_abi]] OnceWith final
    -    : public IteratorBase, ItemT> {
    +template 
    +class [[nodiscard]] OnceWith final
    +    : public IteratorBase, ItemT> {
      public:
       using Item = ItemT;
     
    +  // Type is Move and (can be) Clone.
    +  OnceWith(OnceWith&&) = default;
    +  OnceWith& operator=(OnceWith&&) = default;
    +
    +  // sus::mem::Clone trait.
    +  constexpr OnceWith clone() const noexcept
    +    requires(::sus::mem::Clone)
    +  {
    +    return OnceWith(sus::clone(gen_));
    +  }
    +
       // sus::iter::Iterator trait.
    -  Option next() noexcept {
    -    return gen_.take().map([](auto&& gen) { return ::sus::fn::call_mut(gen); });
    +  constexpr Option next() noexcept {
    +    return gen_.take().map(
    +        [](auto&& gen) -> Item { return ::sus::fn::call_mut(gen); });
       }
       /// sus::iter::Iterator trait.
    -  SizeHint size_hint() const noexcept {
    +  constexpr SizeHint size_hint() const noexcept {
         ::sus::num::usize rem = gen_.is_some() ? 1u : 0u;
         return SizeHint(rem, ::sus::Option<::sus::num::usize>(rem));
       }
       // sus::iter::DoubleEndedIterator trait.
    -  Option next_back() noexcept {
    -    return gen_.take().map([](auto&& gen) { return ::sus::fn::call_mut(gen); });
    +  constexpr Option next_back() noexcept {
    +    return gen_.take().map(
    +        [](auto&& gen) -> Item { return ::sus::fn::call_mut(gen); });
       }
       // sus::iter::ExactSizeIterator trait.
    -  usize exact_size_hint() const noexcept { return gen_.is_some() ? 1u : 0u; }
    +  constexpr usize exact_size_hint() const noexcept {
    +    return gen_.is_some() ? 1u : 0u;
    +  }
     
      private:
    -  friend OnceWith sus::iter::once_with(
    -      ::sus::fn::FnMutBox gen) noexcept;
    +  friend constexpr OnceWith sus::iter::once_with(
    +      GenFn gen) noexcept;
     
    -  OnceWith(::sus::fn::FnMutBox gen)
    -      : gen_(sus::Option<::sus::fn::FnMutBox>(::sus::move(gen))) {
    -  }
    +  constexpr OnceWith(GenFn gen) : gen_(sus::Option(::sus::move(gen))) {}
     
    -  Option<::sus::fn::FnMutBox> gen_;
    +  Option gen_;
     
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(gen_));
    +  sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn,
    +                                           decltype(gen_));
     };
     
     }  // namespace sus::iter
    diff --git a/sus/iter/once_with_unittest.cc b/sus/iter/once_with_unittest.cc
    index 5f575dcbf..d6e690b8c 100644
    --- a/sus/iter/once_with_unittest.cc
    +++ b/sus/iter/once_with_unittest.cc
    @@ -44,4 +44,8 @@ TEST(OnceWith, NextBack) {
       EXPECT_EQ(ow.next_back(), sus::none());
     }
     
    +// constexpr, and verifies that the return type can be converted to the Item
    +// type.
    +static_assert(sus::iter::once_with([] { return 5; }).sum() == 5);
    +
     }  // namespace
    diff --git a/sus/iter/repeat_with.h b/sus/iter/repeat_with.h
    index 08ab06b4f..23f49c714 100644
    --- a/sus/iter/repeat_with.h
    +++ b/sus/iter/repeat_with.h
    @@ -14,7 +14,7 @@
     
     #pragma once
     
    -#include "sus/fn/fn_box_defn.h"
    +#include "sus/fn/fn_concepts.h"
     #include "sus/iter/iterator_defn.h"
     #include "sus/mem/move.h"
     #include "sus/mem/relocate.h"
    @@ -23,7 +23,7 @@ namespace sus::iter {
     
     using ::sus::option::Option;
     
    -template 
    +template 
     class RepeatWith;
     
     /// Creates a new iterator that repeats elements of type `Item` endlessly by
    @@ -46,40 +46,52 @@ class RepeatWith;
     /// sus::check(r.next().unwrap() == 3_u16);
     /// sus::check(r.next().unwrap() == 3_u16);
     /// ```
    -template 
    -inline RepeatWith repeat_with(::sus::fn::FnMutBox gen) noexcept {
    -  return RepeatWith(::sus::move(gen));
    +template  GenFn>
    +constexpr inline RepeatWith repeat_with(GenFn gen) noexcept {
    +  return RepeatWith(::sus::move(gen));
     }
     
     /// An Iterator that walks over at most a single Item.
    -template 
    -class [[nodiscard]] [[sus_trivial_abi]] RepeatWith final
    -    : public IteratorBase, ItemT> {
    +template 
    +class [[nodiscard]] RepeatWith final
    +    : public IteratorBase, ItemT> {
      public:
       using Item = ItemT;
     
    +  // Type is Move and (can be) Clone.
    +  RepeatWith(RepeatWith&&) = default;
    +  RepeatWith& operator=(RepeatWith&&) = default;
    +
    +  // sus::mem::Clone trait.
    +  constexpr RepeatWith clone() const noexcept
    +    requires(::sus::mem::Clone)
    +  {
    +    return RepeatWith(sus::clone(gen_));
    +  }
    +
       // sus::iter::Iterator trait.
    -  Option next() noexcept {
    +  constexpr Option next() noexcept {
         return ::sus::some(::sus::fn::call_mut(gen_));
       }
       /// sus::iter::Iterator trait.
    -  SizeHint size_hint() const noexcept {
    +  constexpr SizeHint size_hint() const noexcept {
         return SizeHint(usize::MAX, ::sus::Option<::sus::num::usize>());
       }
       // sus::iter::DoubleEndedIterator trait.
    -  Option next_back() noexcept {
    +  constexpr Option next_back() noexcept {
         return ::sus::some(::sus::fn::call_mut(gen_));
       }
     
      private:
    -  friend RepeatWith sus::iter::repeat_with(
    -      ::sus::fn::FnMutBox gen) noexcept;
    +  friend constexpr RepeatWith sus::iter::repeat_with(
    +      GenFn gen) noexcept;
     
    -  RepeatWith(::sus::fn::FnMutBox gen) : gen_(::sus::move(gen)) {}
    +  constexpr RepeatWith(GenFn gen) : gen_(::sus::move(gen)) {}
     
    -  ::sus::fn::FnMutBox gen_;
    +  GenFn gen_;
     
    -  sus_class_trivially_relocatable(::sus::marker::unsafe_fn, decltype(gen_));
    +  sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn,
    +                                           decltype(gen_));
     };
     
     }  // namespace sus::iter
    diff --git a/sus/iter/repeat_with_unittest.cc b/sus/iter/repeat_with_unittest.cc
    index 17074ecf3..9dbcb1078 100644
    --- a/sus/iter/repeat_with_unittest.cc
    +++ b/sus/iter/repeat_with_unittest.cc
    @@ -46,4 +46,9 @@ TEST(RepeatWith, NextBack) {
       EXPECT_EQ(o.next_back(), sus::some(3_u16));
     }
     
    +// constexpr, and verifies that the return type can be converted to the Item
    +// type.
    +static_assert(sus::iter::repeat_with([] { return 3; }).take(4u).sum() ==
    +              3 * 4);
    +
     }  // namespace
    diff --git a/sus/iter/successors.h b/sus/iter/successors.h
    index 2872f6006..9ca89e28b 100644
    --- a/sus/iter/successors.h
    +++ b/sus/iter/successors.h
    @@ -14,7 +14,7 @@
     
     #pragma once
     
    -#include "sus/fn/fn_box_defn.h"
    +#include "sus/fn/fn_concepts.h"
     #include "sus/iter/iterator_defn.h"
     #include "sus/mem/move.h"
     #include "sus/mem/relocate.h"
    @@ -23,7 +23,7 @@ namespace sus::iter {
     
     using ::sus::option::Option;
     
    -template 
    +template 
     class Successors;
     
     /// Creates a new iterator where each successive item is computed based on the
    @@ -41,32 +41,42 @@ class Successors;
     ///     sus::move(powers_of_10).collect>() ==
     ///     sus::Slice::from({1_u16, 10_u16, 100_u16, 1000_u16, 10000_u16}));
     /// ```
    -template 
    -inline Successors successors(
    -    Option first,
    -    ::sus::fn::FnMutBox(const Item&)> func) noexcept {
    -  return Successors(::sus::move(first), ::sus::move(func));
    +template (const Item&)> GenFn>
    +constexpr inline Successors successors(Option first,
    +                                                    GenFn func) noexcept {
    +  return Successors(::sus::move(first), ::sus::move(func));
     }
     
     /// An Iterator that generates each item from a function that takes the previous
     /// item.
     ///
     /// This type is created by `sus::iter::successors()`.
    -template 
    +template 
     class [[nodiscard]] Successors final
    -    : public IteratorBase, ItemT> {
    +    : public IteratorBase, ItemT> {
      public:
       using Item = ItemT;
     
    +  // Type is Move and (can be) Clone.
    +  Successors(Successors&&) = default;
    +  Successors& operator=(Successors&&) = default;
    +
    +  // sus::mem::Clone trait.
    +  constexpr Successors clone() const noexcept
    +    requires(::sus::mem::Clone)
    +  {
    +    return Successors(sus::clone(next_), sus::clone(func_));
    +  }
    +
       // sus::iter::Iterator trait.
    -  Option next() noexcept {
    +  constexpr Option next() noexcept {
         Option item = next_.take();
         if (item.is_some()) next_ = ::sus::fn::call_mut(func_, item.as_value());
         return item;
       }
     
       /// sus::iter::Iterator trait.
    -  SizeHint size_hint() const noexcept {
    +  constexpr SizeHint size_hint() const noexcept {
         if (next_.is_some())
           return SizeHint(1u, ::sus::Option<::sus::num::usize>());
         else
    @@ -74,16 +84,14 @@ class [[nodiscard]] Successors final
       }
     
      private:
    -  friend Successors sus::iter::successors(
    -      Option first,
    -      ::sus::fn::FnMutBox(const Item&)> func) noexcept;
    +  friend constexpr Successors sus::iter::successors(
    +      Option first, GenFn func) noexcept;
     
    -  Successors(Option first,
    -             ::sus::fn::FnMutBox(const Item&)>&& func)
    +  constexpr Successors(Option first, GenFn func)
           : next_(::sus::move(first)), func_(::sus::move(func)) {}
     
       Option next_;
    -  ::sus::fn::FnMutBox(const Item&)> func_;
    +  GenFn func_;
     
       sus_class_trivially_relocatable_if_types(::sus::marker::unsafe_fn,
                                                decltype(next_), decltype(func_));
    diff --git a/sus/iter/successors_unittest.cc b/sus/iter/successors_unittest.cc
    index ae741126f..43e7c2525 100644
    --- a/sus/iter/successors_unittest.cc
    +++ b/sus/iter/successors_unittest.cc
    @@ -27,4 +27,39 @@ TEST(Successors, Example) {
           sus::Slice::from({1_u16, 10_u16, 100_u16, 1000_u16, 10000_u16}));
     }
     
    +TEST(Successors, Some) {
    +  auto empty = sus::iter::successors(
    +      sus::some(2), [](i32 n) -> sus::Option { return sus::some(n + 1); });
    +  EXPECT_EQ(empty.size_hint().lower, 1u);
    +  EXPECT_EQ(empty.size_hint().upper, sus::none());
    +  EXPECT_EQ(empty.next().unwrap(), 2);
    +  EXPECT_EQ(empty.next().unwrap(), 3);
    +  EXPECT_EQ(empty.next().unwrap(), 4);
    +}
    +
    +TEST(Successors, None) {
    +  auto empty = sus::iter::successors(
    +      sus::none(), [](i32 n) -> sus::Option { return sus::some(n + 1); });
    +  EXPECT_EQ(empty.size_hint().lower, 0u);
    +  EXPECT_EQ(empty.size_hint().upper, sus::some(0u));
    +  EXPECT_EQ(empty.next().is_none(), true);
    +}
    +
    +// constexpr, and verifies that the return type can be converted to the Item
    +// type.
    +static_assert(sus::iter::successors(sus::some(2),
    +                                         [](i32 i) -> sus::Option {
    +                                           return sus::some(i + 1);
    +                                         })
    +                  .take(4u)
    +                  .sum() == 2 + 3 + 4 + 5);
    +
    +// Longer iteration.
    +static_assert(sus::iter::successors(sus::some(2),
    +                                         [](i32 i) {
    +                                           return sus::Option(i);
    +                                         })
    +                  .take(100u)
    +                  .sum() == 2 * 100);
    +
     }  // namespace
    diff --git a/sus/mem/forward.h b/sus/mem/forward.h
    index 1e957a4a4..e4c4ff887 100644
    --- a/sus/mem/forward.h
    +++ b/sus/mem/forward.h
    @@ -21,7 +21,7 @@
     
     namespace sus::mem {
     
    -/// Passes a reference as an argument while preserving the reference type.
    +/// Move from non-reference values but pass through and preserve references.
     ///
     /// Typically, passing an rvalue reference will convert it to an lvalue. Using
     /// `sus::forward(t)` on an rvalue reference `T&& t` will preserve the rvalue
    @@ -35,11 +35,13 @@ namespace sus::mem {
     ///
     /// In the common case, when you want to receive a parameter that will be moved,
     /// it should be received by value. However, library implementors sometimes with
    -/// to receive an *rvalue reference*. If you find yourself needing to `move()`
    -/// from a universal reference instead of `forward()`, such as to construct a
    +/// to receive an *rvalue reference*. If you find yourself needing to
    +/// [`move()`]($sus::mem::move) from a universal reference instead of
    +/// [`forward()`]($sus::mem::forward), such as to construct a
     /// value type `T` from a universal reference `T&&` without introducing a copy,
    -/// use `IsMoveRef` to constrain the universal reference to be an rvalue, and
    -/// use `move()` instead of `forward()`.
    +/// use [`IsMoveRef`]($sus::mem::IsMoveRef) to constrain the universal reference
    +/// to be an rvalue, and use [`move()`]($sus::mem::move) instead of
    +/// [`forward()`]($sus::mem::forward).
     template 
     sus_pure_const sus_always_inline constexpr T&& forward(
         std::remove_reference_t& t) noexcept {
    diff --git a/sus/mem/move_unittest.cc b/sus/mem/move_unittest.cc
    index 657123141..46e619620 100644
    --- a/sus/mem/move_unittest.cc
    +++ b/sus/mem/move_unittest.cc
    @@ -28,7 +28,7 @@ struct NonTrivial {
     
     // clang-format off
     template 
    -concept can_move = requires(T t) {
    +concept can_move = requires(T& t) {
       { move(t) };
     };
     // clang-format on
    diff --git a/sus/mem/never_value.h b/sus/mem/never_value.h
    index e230e1c65..88a5b791f 100644
    --- a/sus/mem/never_value.h
    +++ b/sus/mem/never_value.h
    @@ -72,14 +72,17 @@ struct NeverValueAccess {
       static constexpr bool has_field = false;
     };
     
    +/// Whether the type `T` has a never-value field.
     template 
    -struct NeverValueAccess {
    -  /// Whether the type `T` has a never-value field.
    +struct NeverValueChecker {
       static constexpr bool has_field = requires {
         std::declval()._sus_Unsafe_NeverValueIsConstructed(
             ::sus::marker::unsafe_fn);
       };
    +};
     
    +template 
    +struct NeverValueAccess {
       constexpr NeverValueAccess() = default;
     
       template 
    @@ -89,7 +92,7 @@ struct NeverValueAccess {
       /// Checks if the never-value field is set to the never-value, returning false
       /// if it is.
       sus_pure constexpr sus_always_inline bool is_constructed() const noexcept
    -    requires(has_field)
    +    requires(NeverValueChecker::has_field)
       {
         return t_._sus_Unsafe_NeverValueIsConstructed(::sus::marker::unsafe_fn);
       }
    @@ -97,7 +100,7 @@ struct NeverValueAccess {
       /// Sets the never-value field to the destroy-value.
       constexpr sus_always_inline void set_destroy_value(
           ::sus::marker::UnsafeFnMarker) noexcept
    -    requires(has_field)
    +    requires(NeverValueChecker::has_field)
       {
         t_._sus_Unsafe_NeverValueSetDestroyValue(::sus::marker::unsafe_fn);
       }
    @@ -126,7 +129,7 @@ struct NeverValueAccess {
     /// the field will be set to a special destroy-value before the destructor is
     /// called.
     template 
    -concept NeverValueField = __private::NeverValueAccess::has_field;
    +concept NeverValueField = __private::NeverValueChecker::has_field;
     
     }  // namespace sus::mem
     
    @@ -151,6 +154,8 @@ concept NeverValueField = __private::NeverValueAccess::has_field;
                                                                                    \
       template                                                              \
       friend struct ::sus::mem::__private::NeverValueAccess;                       \
    +  template                                                              \
    +  friend struct ::sus::mem::__private::NeverValueChecker;                      \
                                                                                    \
       sus_pure constexpr bool _sus_Unsafe_NeverValueIsConstructed(                 \
           ::sus::marker::UnsafeFnMarker) const noexcept {                          \
    diff --git a/sus/num/overflow_integer.h b/sus/num/overflow_integer.h
    index 6a8152e24..7d53d2c15 100644
    --- a/sus/num/overflow_integer.h
    +++ b/sus/num/overflow_integer.h
    @@ -28,28 +28,53 @@ namespace sus::num {
     /// An integer type that handles overflow instead of panicing.
     ///
     /// The value inside the integer can be accessed or unwrapped like with an
    -/// `Option`, which will panic if the integer has overflowed. Or it can be
    -/// converted into an `Option` that will represent the overflow state as `None`.
    +/// [`Option`]($sus::option::Option), which will panic if the integer has
    +/// overflowed. Or it can be converted into an [`Option`]($sus::option::Option)
    +/// that will represent the overflow state as `None`.
    +///
    +/// This type is useful for performing a series of operations as a unit, and
    +/// then checking for overflow after. It satisfies the
    +/// [`Sum`]($sus::iter::Sum) and [`Product`]($sus::iter::Product) concepts
    +/// so can be used with [`sum`]($sus::iter::IteratorBase::sum) and
    +/// [`product`]($sus::iter::IteratorBase::product) for iterators over integers.
    +///
    +/// # Examples
    +/// Using OverflowInteger to sum an iterator of integers and look for overflow
    +/// after without panicking.
    +/// ```
    +/// auto a = sus::Array(2, i32::MAX);
    +/// auto maybe_answer =
    +///     a.iter().copied().product>();
    +/// sus::check(maybe_answer.is_overflow());
    +/// ```
     template <::sus::num::Integer I>
     class OverflowInteger {
      public:
    -  // Default constructs OverflowInteger with the default value of the inner
    +  // Default constructs `OverflowInteger` with the default value of the inner
       // integer type `I`.
       explicit constexpr OverflowInteger() noexcept
         requires(::sus::construct::Default)
           : v_(Option(I())) {}
     
    -  /// Constructs an OverflowInteger from the same subspace integer type.
    -  template  U>
    -  explicit constexpr OverflowInteger(U u) noexcept
    -      : v_(Option(::sus::move(u))) {}
    +  /// Constructs an `OverflowInteger` from the same subspace integer type.
    +  ///
    +  /// # Implementation note
    +  ///
    +  /// Because `OverflowInteger` is constructible from a smaller integer, but
    +  /// `I` is also constructible from a smaller integer, which can then be used
    +  /// to construct `OverflowInteger`, on MSVC this conversion becomes ambiguous.
    +  /// So we use `convertible_to` to make the constructor a template,
    +  /// which allows the compiler to choose one.
    +  /// https://developercommunity.visualstudio.com/t/Ambiguous-conversion-with-two-paths-of-d/10461863
    +  explicit constexpr OverflowInteger(std::convertible_to auto u) noexcept
    +      : v_(Option(sus::move(u))) {}
     
    -  /// Satisfies `sus::construct::From, U>` if the inner
    -  /// integer type `I` satisfies `sus::construct::From`.
    +  /// Satisfies `sus::construct::From, U>` if the
    +  /// `OverflowInteger` is constructible from `U`.
       template 
    -    requires(::sus::construct::From)
    +    requires(std::constructible_from)
       sus_pure static constexpr OverflowInteger from(U u) noexcept {
    -    return OverflowInteger(::sus::move_into(u));
    +    return OverflowInteger(u);
       }
     
       /// Satisfies `sus::construct::TryFrom, U>` if the inner
    @@ -80,7 +105,7 @@ class OverflowInteger {
       /// If an iterator yields a subspace integer type, `iter.product()` would
       /// panic on overflow. So instead `iter.product>()` can be
       /// used (for integer type `T`) which will perform the product computation and
    -  /// return an OverflowInteger without ever panicking.
    +  /// return an `OverflowInteger` without ever panicking.
       static constexpr OverflowInteger from_product(
           ::sus::iter::Iterator auto&& it) noexcept
         requires(::sus::mem::IsMoveRef)
    diff --git a/sus/num/overflow_integer_unittest.cc b/sus/num/overflow_integer_unittest.cc
    index ba4951bd6..490ac02df 100644
    --- a/sus/num/overflow_integer_unittest.cc
    +++ b/sus/num/overflow_integer_unittest.cc
    @@ -18,6 +18,7 @@
     
     #include "googletest/include/gtest/gtest.h"
     #include "sus/collections/array.h"
    +#include "sus/iter/iterator.h"
     #include "sus/num/signed_integer.h"
     #include "sus/num/unsigned_integer.h"
     #include "sus/prelude.h"
    @@ -101,6 +102,13 @@ TEST(OverflowInteger, TryFrom) {
                 sus::num::TryFromIntError::with_out_of_bounds());
     }
     
    +TEST(OverflowInteger, Example_Iterator) {
    +  auto a = sus::Array(2, i32::MAX);
    +  auto maybe_answer =
    +      a.iter().copied().product>();
    +  sus::check(maybe_answer.is_overflow());  // Overflow happened.
    +}
    +
     TEST(OverflowInteger, FromProduct) {
       static_assert(::sus::iter::Product, i32>);
       static_assert(::sus::iter::Product>);
    @@ -113,6 +121,14 @@ TEST(OverflowInteger, FromProduct) {
         static_assert(std::same_as>);
         EXPECT_EQ(o.to_option(), sus::None);
       }
    +  // Reference iterator.
    +  {
    +    auto a = sus::Array(2, i32::MAX);
    +    decltype(auto) o =
    +        a.iter().copied().product>();
    +    static_assert(std::same_as>);
    +    EXPECT_EQ(o.to_option(), sus::None);
    +  }
       // To OverflowInteger without overflow.
       {
         auto a = sus::Array(2, 4);
    @@ -131,8 +147,8 @@ TEST(OverflowInteger, FromProduct) {
       }
       // Iterating OverflowInteger types without overflow.
       {
    -    auto a = sus::Array, 2>(
    -        OverflowInteger(2), OverflowInteger(4));
    +    auto a = sus::Array, 2>(OverflowInteger(2),
    +                                                 OverflowInteger(4));
         decltype(auto) o = sus::move(a).into_iter().product();
         static_assert(std::same_as>);
         EXPECT_EQ(o.to_option().unwrap(), 2 * 4);
    @@ -164,9 +180,8 @@ TEST(OverflowInteger, AsValue) {
         auto lvalue = OverflowInteger(i32::MAX);
         EXPECT_EQ(lvalue.as_value_unchecked(unsafe_fn), i32::MAX);
         EXPECT_EQ(OverflowInteger(i32::MAX).as_value(), i32::MAX);
    -    EXPECT_EQ(
    -        OverflowInteger(i32::MAX).as_value_unchecked(unsafe_fn),
    -        i32::MAX);
    +    EXPECT_EQ(OverflowInteger(i32::MAX).as_value_unchecked(unsafe_fn),
    +              i32::MAX);
       }
     }
     
    @@ -213,8 +228,7 @@ TEST(OverflowIntegerDeathTest, AsValueMutOverflow) {
     TEST(OverflowInteger, Unwrap) {
       EXPECT_EQ(OverflowInteger(i32::MAX).unwrap(), i32::MAX);
       static_assert(
    -      std::same_as(i32::MAX).unwrap()),
    -                   i32>);
    +      std::same_as(i32::MAX).unwrap()), i32>);
       EXPECT_EQ(OverflowInteger(i32::MAX).unwrap_unchecked(unsafe_fn),
                 i32::MAX);
     }
    @@ -225,10 +239,8 @@ TEST(OverflowInteger, ToOption) {
       lvalue += 1;
       EXPECT_EQ(lvalue.to_option(), sus::none());
     
    -  EXPECT_EQ(OverflowInteger(i32::MAX).to_option(),
    -            sus::some(i32::MAX));
    -  EXPECT_EQ((OverflowInteger(i32::MAX) + 1).to_option(),
    -            sus::none());
    +  EXPECT_EQ(OverflowInteger(i32::MAX).to_option(), sus::some(i32::MAX));
    +  EXPECT_EQ((OverflowInteger(i32::MAX) + 1).to_option(), sus::none());
     }
     
     TEST(OverflowInteger, MathAssignFromInt) {
    @@ -445,10 +457,8 @@ TEST(OverflowInteger, Eq) {
     
       EXPECT_EQ(OverflowInteger(1) + i32::MAX,
                 OverflowInteger(1) + i32::MAX);
    -  EXPECT_NE(OverflowInteger(5),
    -            OverflowInteger(1) + i32::MAX);
    -  EXPECT_NE(OverflowInteger(1) + i32::MAX,
    -            OverflowInteger(5));
    +  EXPECT_NE(OverflowInteger(5), OverflowInteger(1) + i32::MAX);
    +  EXPECT_NE(OverflowInteger(1) + i32::MAX, OverflowInteger(5));
     }
     
     TEST(OverflowInteger, StrongOrd) {
    @@ -456,17 +466,13 @@ TEST(OverflowInteger, StrongOrd) {
       static_assert(::sus::ops::StrongOrd, i32>);
       static_assert(::sus::ops::StrongOrd>);
     
    -  EXPECT_EQ(OverflowInteger(5) <=> 4_i32,
    -            std::strong_ordering::greater);
    -  EXPECT_EQ(OverflowInteger(5) <=> 6_i32,
    -            std::strong_ordering::less);
    +  EXPECT_EQ(OverflowInteger(5) <=> 4_i32, std::strong_ordering::greater);
    +  EXPECT_EQ(OverflowInteger(5) <=> 6_i32, std::strong_ordering::less);
       EXPECT_EQ(OverflowInteger(5) <=> 5_i32,
                 std::strong_ordering::equivalent);
     
    -  EXPECT_EQ(6_i32 <=> OverflowInteger(5),
    -            std::strong_ordering::greater);
    -  EXPECT_EQ(4_i32 <=> OverflowInteger(5),
    -            std::strong_ordering::less);
    +  EXPECT_EQ(6_i32 <=> OverflowInteger(5), std::strong_ordering::greater);
    +  EXPECT_EQ(4_i32 <=> OverflowInteger(5), std::strong_ordering::less);
       EXPECT_EQ(5_i32 <=> OverflowInteger(5),
                 std::strong_ordering::equivalent);
     
    @@ -477,18 +483,16 @@ TEST(OverflowInteger, StrongOrd) {
       EXPECT_EQ(OverflowInteger(5) <=> OverflowInteger(5),
                 std::strong_ordering::equivalent);
     
    -  EXPECT_EQ(OverflowInteger(1) + i32::MAX <=>
    -                OverflowInteger(1) + i32::MAX,
    -            std::strong_ordering::equivalent);
    +  EXPECT_EQ(
    +      OverflowInteger(1) + i32::MAX <=> OverflowInteger(1) + i32::MAX,
    +      std::strong_ordering::equivalent);
       EXPECT_EQ(OverflowInteger(1) + i32::MAX <=> 0_i32,
                 std::strong_ordering::greater);
       EXPECT_EQ(0_i32 <=> OverflowInteger(1) + i32::MAX,
                 std::strong_ordering::less);
    -  EXPECT_EQ(OverflowInteger(1) + i32::MAX <=>
    -                OverflowInteger(0),
    +  EXPECT_EQ(OverflowInteger(1) + i32::MAX <=> OverflowInteger(0),
                 std::strong_ordering::greater);
    -  EXPECT_EQ(OverflowInteger(0) <=>
    -                OverflowInteger(1) + i32::MAX,
    +  EXPECT_EQ(OverflowInteger(0) <=> OverflowInteger(1) + i32::MAX,
                 std::strong_ordering::less);
     }
     
    diff --git a/sus/num/types.h b/sus/num/types.h
    index 73cb27e56..00c72f49b 100644
    --- a/sus/num/types.h
    +++ b/sus/num/types.h
    @@ -18,34 +18,76 @@
     
     namespace sus {
     
    -/// Safe integer and floating point numerics, and numeric concepts.
    +/// Safe integer (e.g. [`i32`]($sus::num::i32)) and floating point
    +/// (e.g. [`f32`]($sus::num::f32)) numerics, and numeric concepts.
     ///
    -/// This namespace contains safe integer types (i8, i16, u32, usize, etc.) and
    -/// floating point types (f32, f64).
    +/// This namespace contains safe integer types and floating point types.
    +///
    +/// Safe numeric types:
    +/// * Signed integers: [`i8`]($sus::num::i8), [`i16`]($sus::num::i16),
    +///   [`i32`]($sus::num::i32), [`i64`]($sus::num::i64),
    +///   [`isize`]($sus::num::isize).
    +/// * Unsigned integers: [`u8`]($sus::num::u8), [`u16`]($sus::num::u16),
    +///   [`u32`]($sus::num::u32), [`u64`]($sus::num::u64),
    +///   [`usize`]($sus::num::usize), [`uptr`]($sus::num::uptr).
    +/// * Floating point: [`f32`]($sus::num::f32), [`f64`]($sus::num::f64).
    +/// * Portability helper: [`CInt`]
     ///
     /// Additionally, there are Concepts that match against safe numerics, C++
     /// primitive types, and operations with numeric types.
     ///
    +/// The Subspace library numeric types can interoperate with primitive C++
    +/// types, but are safer than primitive C++ types and eliminate many classes of
    +/// bugs that often lead to security vulnerabilities:
    +/// * Integer overflow is not allowed by default, and will
    +///   [`panic`]($sus::assertions::panic) to terminate the
    +///   program. Intentional overflow can be achieved through methods like
    +///   [`wrapping_add`]($sus::num::i32::wrapping_add) or
    +///   [`saturating_mul`]($sus::num::i32::saturating_mul). The
    +///   [`OverflowInteger`]($sus::num::OverflowInteger) type can be used for a
    +///   series of potentially-overflowing operations and unwraps to an integer
    +///   value if-and-only-if no overflow has occured.
    +/// * Integers and floats convert implicitly into each other or into primitive
    +///   types *only* when no data can be lost, otherwise conversions do not
    +///   compile. To convert fallibly and observe data loss, use the
    +///   [`TryFrom`]($sus::construct::TryFrom) concept methods, such as
    +///   `u32::try_from(3_i32)`. To do casting conversions with truncation, use
    +///   [`Transmogrify`]($sus::construct::Transmogrify).
    +/// * No integer promotion. Math on 8-bit and 16-bit integers will not change
    +///   their type, unlike primitive types which convert to (signed) int on any
    +///   math operation.
    +/// * No Undefined Behaviour in conversions. Conversions between all numeric
    +///   types, and between them and primitive types is well-defined for all
    +///   possible values, unlike conversions between primitive integer and
    +///   floating point types which can result in Undefined Behaviour.
    +///
    +/// The numeric types also come with builtin methods to perform common
    +/// operations, such as [`abs`]($sus::num::i32::abs),
    +/// [`pow`]($sus::num::i32::pow), [`log10`]($sus::num::i32::log10), or
    +/// [`leading_ones`]($sus::num::i32::leading_ones).
    +///
     /// # Conversions
     ///
    -/// To convert to and from integer values, use
    -/// [`sus::into`]($sus::construct::into) when
    -/// [`Into`]($sus::construct::Into) is satisfied between the two
    -/// types for lossless conversion. Otherwise use
    -/// [`sus::try_into`]($sus::construct::try_into) when
    -/// [`TryInto`]($sus::construct::TryInto) is satisfied to convert
    -/// and handle cases where the value can not be represented in the target type.
    -///
    -/// To convert between floating point types, use
    -/// [`sus::into(x)`]($sus::construct::into) to losslessly promote `x` to a
    -/// larger type ([`f32`]($sus::num::f32) to [`f64`]($sus::num::f64)) or
    -/// `sus::try_into(x)` to convert `x` to a smaller type
    -/// ([`f64`]($sus::num::f64) to [`f32`]($sus::num::f32)).
    -///
    -/// Use [`sus::mog()`]($sus::construct::mog) to do a lossy type coercion
    -/// (like `static_cast()`) between integer and floating point types, or C++
    -/// primitive integers, floating point, or enums. When converting to a larger
    -/// signed integer type, the value will be sign-extended.
    +/// To explicitly invoke a lossless conversion, use
    +/// [`From`]($sus::construct::From). Use [`Into`]($sus::construct::Into) to
    +/// constain inputs in generic code, and [`sus::into()`]($sus::construct::into)
    +/// to type-deduce for conversions. Some lossless conversions are also allowed
    +/// to happen implicitly, though explicit conversion is better.
    +///
    +/// To convert and handle the case where data is lost, use
    +/// [`TryFrom`]($sus::construct::TryFrom), or
    +/// [`TryInto`]($sus::construct::TryInto) in generic code. Using
    +/// `T::try_from(U).unwrap()` is a quick way to convert and find out if there
    +/// are values out of range, or to terminate on malicious inputs. Or
    +/// `T::try_from(U).unwrap_or_default()` to convert to the input value or else
    +/// to zero.
    +///
    +/// To convert with truncation/loss of data, like `static_cast`, use
    +/// [`sus::mog()`]($sus::construct::mog). It can convert between
    +/// integers, floats, and enums, for both safe numerics and primitives. See
    +/// [Casting numeric types](
    +/// $sus::construct::Transmogrify#casting-numeric-types) for the rules of
    +/// conversion through [`mog`]($sus::construct::mog).
     namespace num {}
     
     }  // namespace sus
    diff --git a/sus/ops/ord.h b/sus/ops/ord.h
    index 0cc0bbba2..0fc95a285 100644
    --- a/sus/ops/ord.h
    +++ b/sus/ops/ord.h
    @@ -21,7 +21,6 @@
     
     #include "sus/assertions/check.h"
     #include "sus/fn/fn_concepts.h"
    -#include "sus/fn/fn_ref.h"
     #include "sus/macros/lifetimebound.h"
     #include "sus/mem/forward.h"
     
    diff --git a/sus/ops/range.h b/sus/ops/range.h
    index 1bedb475d..715a6fd19 100644
    --- a/sus/ops/range.h
    +++ b/sus/ops/range.h
    @@ -28,7 +28,7 @@ namespace sus::ops {
     /// `RangeBounds` is implemented by Subspace's range types, and produced by
     /// range syntax like `..`, `a..`, `..b`, `..=c`, `d..e`, or `f..=g`.
     template 
    -concept RangeBounds = requires(const T& t, T v, I i) {
    +concept RangeBounds = requires(const T& t, T& v, const I& i) {
       { t.start_bound() } -> std::same_as<::sus::option::Option>;
       { t.end_bound() } -> std::same_as<::sus::option::Option>;
       // Rvalue overloads must not exist as they would return a reference to a
    diff --git a/sus/option/option.h b/sus/option/option.h
    index 7b1964b98..0b868246b 100644
    --- a/sus/option/option.h
    +++ b/sus/option/option.h
    @@ -1887,10 +1887,11 @@ class Option final {
       // storage from a `T` object or a `T&&` (which is received as `T&`).
       template 
       static constexpr inline decltype(auto) move_to_storage(U&& t) {
    -    if constexpr (std::is_reference_v)
    -      return StoragePointer(t);
    -    else
    +    if constexpr (std::is_reference_v) {
    +      return StoragePointer(::sus::forward(t));
    +    } else {
           return ::sus::move(t);
    +    }
       }
     
       /// Constructors for `Some`.
    diff --git a/sus/ptr/nonnull_unittest.cc b/sus/ptr/nonnull_unittest.cc
    index 5de15b9a5..593c337e4 100644
    --- a/sus/ptr/nonnull_unittest.cc
    +++ b/sus/ptr/nonnull_unittest.cc
    @@ -153,7 +153,7 @@ TEST(NonNull, AsRef) {
     }
     
     template 
    -concept AsRefMutExists = requires(T t) { t.as_mut(); };
    +concept AsRefMutExists = requires(T& t) { t.as_mut(); };
     
     TEST(NonNull, AsRefMut) {
       int i = 1;
    @@ -180,7 +180,7 @@ TEST(NonNull, AsPtr) {
     }
     
     template 
    -concept AsPtrMutExists = requires(T t) { t.as_mut_ptr(); };
    +concept AsPtrMutExists = requires(T& t) { t.as_mut_ptr(); };
     
     TEST(NonNull, AsPtrMut) {
       int i = 1;
    diff --git a/sus/result/result.h b/sus/result/result.h
    index 510cd4c9c..ef115deb9 100644
    --- a/sus/result/result.h
    +++ b/sus/result/result.h
    @@ -23,7 +23,7 @@
     #include "fmt/format.h"
     #include "sus/assertions/check.h"
     #include "sus/assertions/unreachable.h"
    -#include "sus/fn/fn_ref.h"
    +#include "sus/fn/fn_concepts.h"
     #include "sus/iter/into_iterator.h"
     #include "sus/iter/iterator_defn.h"
     #include "sus/iter/once.h"
    @@ -47,7 +47,7 @@
     namespace sus {
     /// The [`Result`]($sus::result::Result) type, and the
     /// [`ok`]($sus::result::ok) and [`err`]($sus::result::err)
    -/// type-deduction functions.
    +/// type-deduction constructor functions.
     namespace result {}
     }  // namespace sus
     
    diff --git a/sus/tuple/tuple.h b/sus/tuple/tuple.h
    index c46df7f2f..89ef670a9 100644
    --- a/sus/tuple/tuple.h
    +++ b/sus/tuple/tuple.h
    @@ -44,7 +44,7 @@
     
     namespace sus {
     /// The [`Tuple`]($sus::tuple_type::Tuple) type, and the
    -/// [`tuple`]($sus::tuple_type::tuple) type-deduction function.
    +/// [`tuple`]($sus::tuple_type::tuple) type-deduction constructor function.
     namespace tuple_type {}
     }  // namespace sus
     
    diff --git a/tools/run_subdoc.bat b/tools/run_subdoc.bat
    index 25cd41264..0767f554e 100644
    --- a/tools/run_subdoc.bat
    +++ b/tools/run_subdoc.bat
    @@ -9,4 +9,4 @@ out\subdoc\subdoc -p out --out docs ^
         --project-logo logo.png ^
         --project-name Subspace ^
         --ignore-bad-code-links ^
    -    subspace/sus/num/uptr
    +    subspace/sus/num/uptr sus/boxed/box_