pw_span: Begin transitioning to std::span

- Provide an implementation of std::span accessible from the <span>
  header.
- Add tests to confirm that std::span and pw::span implicitly convert to
  one another.

Change-Id: I02e8ffc289975810b51ef32ffbc3b59a6e037caf
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/12760
Commit-Queue: Wyatt Hepler <hepler@google.com>
Reviewed-by: Keir Mierle <keir@google.com>
diff --git a/pw_span/BUILD b/pw_span/BUILD
index 47129f2..528106a 100644
--- a/pw_span/BUILD
+++ b/pw_span/BUILD
@@ -24,7 +24,11 @@
 
 pw_cc_library(
     name = "pw_span",
-    hdrs = ["public/pw_span/span.h"],
+    srcs = ["public/pw_span/internal/span.h"],
+    hdrs = [
+        "public/pw_span/span.h",
+        "public_overrides/span",
+    ],
     includes = ["public"],
     deps = ["//pw_polyfill"],
 )
@@ -37,3 +41,12 @@
         "//pw_unit_test",
     ],
 )
+
+pw_cc_test(
+    name = "pw_span_test",
+    srcs = ["pw_span_test.cc"],
+    deps = [
+        ":pw_span",
+        "//pw_unit_test",
+    ],
+)
diff --git a/pw_span/BUILD.gn b/pw_span/BUILD.gn
index 737f6f5..cd2c881 100644
--- a/pw_span/BUILD.gn
+++ b/pw_span/BUILD.gn
@@ -19,18 +19,27 @@
 import("$dir_pw_docgen/docs.gni")
 import("$dir_pw_unit_test/test.gni")
 config("default_config") {
-  include_dirs = [ "public" ]
+  include_dirs = [
+    "public",
+    "public_overrides",
+  ]
 }
 
 pw_source_set("pw_span") {
   public_configs = [ ":default_config" ]
   public_deps = [ "$dir_pw_polyfill" ]
-  public = [ "public/pw_span/span.h" ]
-  sources = public
+  public = [
+    "public/pw_span/span.h",
+    "public_overrides/span",
+  ]
+  sources = [ "public/pw_span/internal/span.h" ]
 }
 
 pw_test_group("tests") {
-  tests = [ ":test" ]
+  tests = [
+    ":test",
+    ":pw_span_test",
+  ]
 }
 
 pw_test("test") {
@@ -38,6 +47,11 @@
   sources = [ "span_test.cc" ]
 }
 
+pw_test("pw_span_test") {
+  deps = [ ":pw_span" ]
+  sources = [ "pw_span_test.cc" ]
+}
+
 pw_doc_group("docs") {
   sources = [ "docs.rst" ]
 }
diff --git a/pw_span/CMakeLists.txt b/pw_span/CMakeLists.txt
index 4b848e2..65644a1 100644
--- a/pw_span/CMakeLists.txt
+++ b/pw_span/CMakeLists.txt
@@ -13,3 +13,4 @@
 # the License.
 
 pw_auto_add_simple_module(pw_span PUBLIC_DEPS pw_polyfill)
+target_include_directories(pw_span PUBLIC public_overrides)
diff --git a/pw_span/docs.rst b/pw_span/docs.rst
index 9fff2f3..b44ba1e 100644
--- a/pw_span/docs.rst
+++ b/pw_span/docs.rst
@@ -9,11 +9,30 @@
 -------
 The ``pw_span`` module provides an implementation of C++20's
 `std::span <https://en.cppreference.com/w/cpp/container/span>`_, which is a
-non-owning view of an array of values. The intent is for ``pw::span``'s
-interface to exactly match ``std::span``.
+non-owning view of an array of values. The intent is for this implementation of
+``std::span`` is to exactly match the C++20 standard.
 
-``pw::span`` is a convenient abstraction that wraps a pointer and a size.
-``pw::span`` is especially useful in APIs. Spans support implicit conversions
+The only header provided by the ``pw_span`` namespace is ``<span>``. It is
+included as if it were coming from the C++ Standard Library. If the C++ library
+provides ``<span>``, the library's version of ``std::span`` is used in place of
+``pw_span``'s.
+
+``pw_span`` requires two include paths -- ``public/`` and ``public_overrides/``.
+The internal implementation header is in ``public/``, and the ``<span>`` header
+that mimics the C++ Standard Library is in ``public_overrides/``.
+
+.. warning::
+
+  Currently, there is a ``pw_span/span.h`` header that provides a ``pw::span``
+  class. ``pw::span`` is deprecated. Do NOT use it in new code. Instead, include
+  ``<span>`` and use ``std::span``. ``pw::span`` will be removed as soon as
+  projects have migrated to ``std::span``.
+
+
+Using std::span
+===============
+``std::span`` is a convenient abstraction that wraps a pointer and a size.
+``std::span`` is especially useful in APIs. Spans support implicit conversions
 from C arrays, ``std::array``, or any STL-style container, such as
 ``std::string_view``.
 
@@ -30,33 +49,35 @@
     ProcessBuffer(data_pointer, data_size);
   }
 
-Pointer and size arguments can be replaced with a ``pw::span``:
+Pointer and size arguments can be replaced with a ``std::span``:
 
 .. code-block:: cpp
 
-  // With pw::span, the buffer is passed as a single argument.
-  bool ProcessBuffer(const pw::span<uint8_t>& buffer);
+  #include <span>
+
+  // With std::span, the buffer is passed as a single argument.
+  bool ProcessBuffer(std::span<uint8_t> buffer);
 
   bool DoStuff() {
     ProcessBuffer(c_array);
     ProcessBuffer(array_object);
-    ProcessBuffer(pw::span(data_pointer, data_size));
+    ProcessBuffer(std::span(data_pointer, data_size));
   }
 
 .. tip::
-  Use ``pw::span<std::byte>`` or ``pw::span<const std::byte>`` to represent
-  spans of binary data. Use ``pw::as_bytes`` or ``pw::as_writeable_bytes``
+  Use ``std::span<std::byte>`` or ``std::span<const std::byte>`` to represent
+  spans of binary data. Use ``std::as_bytes`` or ``std::as_writeable_bytes``
   to convert any span to a byte span.
 
   .. code-block:: cpp
 
-    void ProcessData(pw::span<const std::byte> data);
+    void ProcessData(std::span<const std::byte> data);
 
     void DoStuff() {
       std::array<AnyType, 7> data = { ... };
-      ProcessData(pw::as_bytes(pw::span(data)));
+      ProcessData(std::as_bytes(std::span(data)));
     }
 
 Compatibility
 =============
-C++17
+Works with C++11, but some features require C++17.
diff --git a/pw_span/public/pw_span/internal/span.h b/pw_span/public/pw_span/internal/span.h
new file mode 100644
index 0000000..f3ac9be
--- /dev/null
+++ b/pw_span/public/pw_span/internal/span.h
@@ -0,0 +1,471 @@
+// Copyright 2020 The Pigweed Authors
+//
+// 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.
+
+// std::span is a stand-in for C++20's std::span. Do NOT include this header
+// directly; instead, include it as <span>.
+//
+// A span is a non-owning array view class. It refers to an external array by
+// storing a pointer and length. Unlike std::array, the size does not have to be
+// a template parameter, so this class can be used to without stating its size.
+//
+// This file a modified version of base::span from Chromium:
+//   https://chromium.googlesource.com/chromium/src/+/d93ae920e4309682deb9352a4637cfc2941c1d1f/base/containers/span.h
+//
+// In order to minimize changes from the original, this file does NOT fully
+// adhere to Pigweed's style guide.
+//
+// A few changes were made to the Chromium version of span. These include:
+//   - Use std::data and std::size instead of base::* versions.
+//   - Rename base namespace to std.
+//   - Rename internal namespace to pw_span_internal.
+//   - Remove uses of checked_iterators.h and CHECK.
+//   - Replace make_span functions with C++17 class template deduction guides.
+//   - Use std::byte instead of uint8_t for compatibility with std::span.
+//
+#pragma once
+
+#include <algorithm>
+#include <array>
+#include <cstddef>
+#include <iterator>
+#include <limits>
+#include <type_traits>
+#include <utility>
+
+#include "pw_polyfill/language_features.h"
+
+// Pigweed: Disable the asserts from Chromium for now.
+#define _PW_SPAN_ASSERT(arg)
+
+namespace std {
+
+// [views.constants]
+constexpr size_t dynamic_extent = std::numeric_limits<size_t>::max();
+
+template <typename T, size_t Extent = dynamic_extent>
+class span;
+
+namespace pw_span_internal {
+
+template <typename T>
+struct ExtentImpl : std::integral_constant<size_t, dynamic_extent> {};
+
+template <typename T, size_t N>
+struct ExtentImpl<T[N]> : std::integral_constant<size_t, N> {};
+
+template <typename T, size_t N>
+struct ExtentImpl<std::array<T, N>> : std::integral_constant<size_t, N> {};
+
+template <typename T, size_t N>
+struct ExtentImpl<std::span<T, N>> : std::integral_constant<size_t, N> {};
+
+template <typename T>
+using Extent = ExtentImpl<std::remove_cv_t<std::remove_reference_t<T>>>;
+
+template <typename T>
+struct IsSpanImpl : std::false_type {};
+
+template <typename T, size_t Extent>
+struct IsSpanImpl<span<T, Extent>> : std::true_type {};
+
+template <typename T>
+using IsSpan = IsSpanImpl<std::decay_t<T>>;
+
+template <typename T>
+struct IsStdArrayImpl : std::false_type {};
+
+template <typename T, size_t N>
+struct IsStdArrayImpl<std::array<T, N>> : std::true_type {};
+
+template <typename T>
+using IsStdArray = IsStdArrayImpl<std::decay_t<T>>;
+
+template <typename T>
+using IsCArray = std::is_array<std::remove_reference_t<T>>;
+
+template <typename From, typename To>
+using IsLegalDataConversion = std::is_convertible<From (*)[], To (*)[]>;
+
+template <typename Container, typename T>
+using ContainerHasConvertibleData = IsLegalDataConversion<
+    std::remove_pointer_t<decltype(std::data(std::declval<Container>()))>,
+    T>;
+
+template <typename Container>
+using ContainerHasIntegralSize =
+    std::is_integral<decltype(std::size(std::declval<Container>()))>;
+
+template <typename From, size_t FromExtent, typename To, size_t ToExtent>
+using EnableIfLegalSpanConversion =
+    std::enable_if_t<(ToExtent == dynamic_extent || ToExtent == FromExtent) &&
+                     IsLegalDataConversion<From, To>::value>;
+
+// SFINAE check if Array can be converted to a span<T>.
+template <typename Array, typename T, size_t Extent>
+using EnableIfSpanCompatibleArray =
+    std::enable_if_t<(Extent == dynamic_extent ||
+                      Extent == pw_span_internal::Extent<Array>::value) &&
+                     ContainerHasConvertibleData<Array, T>::value>;
+
+// SFINAE check if Container can be converted to a span<T>.
+template <typename Container, typename T>
+using IsSpanCompatibleContainer =
+    std::conditional_t<!IsSpan<Container>::value &&
+                           !IsStdArray<Container>::value &&
+                           !IsCArray<Container>::value &&
+                           ContainerHasConvertibleData<Container, T>::value &&
+                           ContainerHasIntegralSize<Container>::value,
+                       std::true_type,
+                       std::false_type>;
+
+template <typename Container, typename T>
+using EnableIfSpanCompatibleContainer =
+    std::enable_if_t<IsSpanCompatibleContainer<Container, T>::value>;
+
+template <typename Container, typename T, size_t Extent>
+using EnableIfSpanCompatibleContainerAndSpanIsDynamic =
+    std::enable_if_t<IsSpanCompatibleContainer<Container, T>::value &&
+                     Extent == dynamic_extent>;
+
+// A helper template for storing the size of a span. Spans with static extents
+// don't require additional storage, since the extent itself is specified in the
+// template parameter.
+template <size_t Extent>
+class ExtentStorage {
+ public:
+  constexpr explicit ExtentStorage(size_t /* size */) noexcept {}
+  constexpr size_t size() const noexcept { return Extent; }
+};
+
+// Specialization of ExtentStorage for dynamic extents, which do require
+// explicit storage for the size.
+template <>
+struct ExtentStorage<dynamic_extent> {
+  constexpr explicit ExtentStorage(size_t size) noexcept : size_(size) {}
+  constexpr size_t size() const noexcept { return size_; }
+
+ private:
+  size_t size_;
+};
+
+}  // namespace pw_span_internal
+
+// A span is a value type that represents an array of elements of type T. Since
+// it only consists of a pointer to memory with an associated size, it is very
+// light-weight. It is cheap to construct, copy, move and use spans, so that
+// users are encouraged to use it as a pass-by-value parameter. A span does not
+// own the underlying memory, so care must be taken to ensure that a span does
+// not outlive the backing store.
+//
+// span is somewhat analogous to StringPiece, but with arbitrary element types,
+// allowing mutation if T is non-const.
+//
+// span is implicitly convertible from C++ arrays, as well as most [1]
+// container-like types that provide a data() and size() method (such as
+// std::vector<T>). A mutable span<T> can also be implicitly converted to an
+// immutable span<const T>.
+//
+// Consider using a span for functions that take a data pointer and size
+// parameter: it allows the function to still act on an array-like type, while
+// allowing the caller code to be a bit more concise.
+//
+// For read-only data access pass a span<const T>: the caller can supply either
+// a span<const T> or a span<T>, while the callee will have a read-only view.
+// For read-write access a mutable span<T> is required.
+//
+// Without span:
+//   Read-Only:
+//     // std::string HexEncode(const uint8_t* data, size_t size);
+//     std::vector<uint8_t> data_buffer = GenerateData();
+//     std::string r = HexEncode(data_buffer.data(), data_buffer.size());
+//
+//  Mutable:
+//     // ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args...);
+//     char str_buffer[100];
+//     SafeSNPrintf(str_buffer, sizeof(str_buffer), "Pi ~= %lf", 3.14);
+//
+// With span:
+//   Read-Only:
+//     // std::string HexEncode(std::span<const uint8_t> data);
+//     std::vector<uint8_t> data_buffer = GenerateData();
+//     std::string r = HexEncode(data_buffer);
+//
+//  Mutable:
+//     // ssize_t SafeSNPrintf(std::span<char>, const char* fmt, Args...);
+//     char str_buffer[100];
+//     SafeSNPrintf(str_buffer, "Pi ~= %lf", 3.14);
+//
+// Spans with "const" and pointers
+// -------------------------------
+//
+// Const and pointers can get confusing. Here are vectors of pointers and their
+// corresponding spans:
+//
+//   const std::vector<int*>        =>  std::span<int* const>
+//   std::vector<const int*>        =>  std::span<const int*>
+//   const std::vector<const int*>  =>  std::span<const int* const>
+//
+// Differences from the C++20 draft
+// --------------------------------
+//
+// http://eel.is/c++draft/views contains the latest C++20 draft of std::span.
+// Chromium tries to follow the draft as close as possible. Differences between
+// the draft and the implementation are documented in subsections below.
+//
+// Differences from [span.cons]:
+// - Constructing a static span (i.e. Extent != dynamic_extent) from a dynamic
+//   sized container (e.g. std::vector) requires an explicit conversion (in the
+//   C++20 draft this is simply UB)
+//
+// Furthermore, all constructors and methods are marked noexcept due to the lack
+// of exceptions in Chromium.
+
+// [span], class template span
+template <typename T, size_t Extent>
+class span : public pw_span_internal::ExtentStorage<Extent> {
+ private:
+  using ExtentStorage = pw_span_internal::ExtentStorage<Extent>;
+
+ public:
+  using element_type = T;
+  using value_type = std::remove_cv_t<T>;
+  using size_type = size_t;
+  using difference_type = ptrdiff_t;
+  using pointer = T*;
+  using reference = T&;
+  using iterator = T*;
+  using reverse_iterator = std::reverse_iterator<iterator>;
+  static constexpr size_t extent = Extent;
+
+  // [span.cons], span constructors, copy, assignment, and destructor
+  constexpr span() noexcept : ExtentStorage(0), data_(nullptr) {
+    static_assert(Extent == dynamic_extent || Extent == 0, "Invalid Extent");
+  }
+
+  constexpr span(T* data, size_t size) noexcept
+      : ExtentStorage(size), data_(data) {
+    _PW_SPAN_ASSERT(Extent == dynamic_extent || Extent == size);
+  }
+
+  // Artificially templatized to break ambiguity for span(ptr, 0).
+  template <typename = void>
+  constexpr span(T* begin, T* end) noexcept : span(begin, end - begin) {
+    // Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
+    _PW_SPAN_ASSERT(begin <= end);
+  }
+
+  template <
+      size_t N,
+      typename =
+          pw_span_internal::EnableIfSpanCompatibleArray<T (&)[N], T, Extent>>
+  constexpr span(T (&array)[N]) noexcept : span(std::data(array), N) {}
+
+  template <typename U,
+            size_t N,
+            typename = pw_span_internal::
+                EnableIfSpanCompatibleArray<std::array<U, N>&, T, Extent>>
+  constexpr span(std::array<U, N>& array) noexcept
+      : span(std::data(array), N) {}
+
+  template <typename U,
+            size_t N,
+            typename = pw_span_internal::
+                EnableIfSpanCompatibleArray<const std::array<U, N>&, T, Extent>>
+  constexpr span(const std::array<U, N>& array) noexcept
+      : span(std::data(array), N) {}
+
+  // Conversion from a container that has compatible std::data() and integral
+  // std::size().
+  template <typename Container,
+            typename = pw_span_internal::
+                EnableIfSpanCompatibleContainerAndSpanIsDynamic<Container&,
+                                                                T,
+                                                                Extent>>
+  constexpr span(Container& container) noexcept
+      : span(std::data(container), std::size(container)) {}
+
+  template <
+      typename Container,
+      typename = pw_span_internal::
+          EnableIfSpanCompatibleContainerAndSpanIsDynamic<const Container&,
+                                                          T,
+                                                          Extent>>
+  constexpr span(const Container& container) noexcept
+      : span(std::data(container), std::size(container)) {}
+
+  constexpr span(const span& other) noexcept = default;
+
+  // Conversions from spans of compatible types and extents: this allows a
+  // span<T> to be seamlessly used as a span<const T>, but not the other way
+  // around. If extent is not dynamic, OtherExtent has to be equal to Extent.
+  template <typename U,
+            size_t OtherExtent,
+            typename = pw_span_internal::
+                EnableIfLegalSpanConversion<U, OtherExtent, T, Extent>>
+  constexpr span(const span<U, OtherExtent>& other)
+      : span(other.data(), other.size()) {}
+
+  PW_CONSTEXPR_FUNCTION span& operator=(const span& other) noexcept = default;
+  ~span() noexcept = default;
+
+  // [span.sub], span subviews
+  template <size_t Count>
+  constexpr span<T, Count> first() const noexcept {
+    static_assert(Count <= Extent, "Count must not exceed Extent");
+    _PW_SPAN_ASSERT(Extent != dynamic_extent || Count <= size());
+    return {data(), Count};
+  }
+
+  template <size_t Count>
+  constexpr span<T, Count> last() const noexcept {
+    static_assert(Count <= Extent, "Count must not exceed Extent");
+    _PW_SPAN_ASSERT(Extent != dynamic_extent || Count <= size());
+    return {data() + (size() - Count), Count};
+  }
+
+  template <size_t Offset, size_t Count = dynamic_extent>
+  constexpr span<T,
+                 (Count != dynamic_extent
+                      ? Count
+                      : (Extent != dynamic_extent ? Extent - Offset
+                                                  : dynamic_extent))>
+  subspan() const noexcept {
+    static_assert(Offset <= Extent, "Offset must not exceed Extent");
+    static_assert(Count == dynamic_extent || Count <= Extent - Offset,
+                  "Count must not exceed Extent - Offset");
+    _PW_SPAN_ASSERT(Extent != dynamic_extent || Offset <= size());
+    _PW_SPAN_ASSERT(Extent != dynamic_extent || Count == dynamic_extent ||
+                    Count <= size() - Offset);
+    return {data() + Offset, Count != dynamic_extent ? Count : size() - Offset};
+  }
+
+  constexpr span<T, dynamic_extent> first(size_t count) const noexcept {
+    // Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
+    _PW_SPAN_ASSERT(count <= size());
+    return {data(), count};
+  }
+
+  constexpr span<T, dynamic_extent> last(size_t count) const noexcept {
+    // Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
+    _PW_SPAN_ASSERT(count <= size());
+    return {data() + (size() - count), count};
+  }
+
+  constexpr span<T, dynamic_extent> subspan(
+      size_t offset, size_t count = dynamic_extent) const noexcept {
+    // Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
+    _PW_SPAN_ASSERT(offset <= size());
+    _PW_SPAN_ASSERT(count == dynamic_extent || count <= size() - offset);
+    return {data() + offset, count != dynamic_extent ? count : size() - offset};
+  }
+
+  // [span.obs], span observers
+  constexpr size_t size() const noexcept { return ExtentStorage::size(); }
+  constexpr size_t size_bytes() const noexcept { return size() * sizeof(T); }
+  [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
+
+  // [span.elem], span element access
+  constexpr T& operator[](size_t idx) const noexcept {
+    // Note: CHECK_LT is not constexpr, hence regular CHECK must be used.
+    _PW_SPAN_ASSERT(idx < size());
+    return *(data() + idx);
+  }
+
+  constexpr T& front() const noexcept {
+    static_assert(Extent == dynamic_extent || Extent > 0,
+                  "Extent must not be 0");
+    _PW_SPAN_ASSERT(Extent != dynamic_extent || !empty());
+    return *data();
+  }
+
+  constexpr T& back() const noexcept {
+    static_assert(Extent == dynamic_extent || Extent > 0,
+                  "Extent must not be 0");
+    _PW_SPAN_ASSERT(Extent != dynamic_extent || !empty());
+    return *(data() + size() - 1);
+  }
+
+  constexpr T* data() const noexcept { return data_; }
+
+  // [span.iter], span iterator support
+  constexpr iterator begin() const noexcept { return data_; }
+  constexpr iterator end() const noexcept { return data_ + size(); }
+
+  constexpr reverse_iterator rbegin() const noexcept {
+    return reverse_iterator(end());
+  }
+  constexpr reverse_iterator rend() const noexcept {
+    return reverse_iterator(begin());
+  }
+
+ private:
+  T* data_;
+};
+
+// span<T, Extent>::extent can not be declared inline prior to C++17, hence this
+// definition is required.
+// template <class T, size_t Extent>
+// constexpr size_t span<T, Extent>::extent;
+
+// [span.objectrep], views of object representation
+template <typename T, size_t X>
+span<const std::byte, (X == dynamic_extent ? dynamic_extent : sizeof(T) * X)>
+as_bytes(span<T, X> s) noexcept {
+  return {reinterpret_cast<const std::byte*>(s.data()), s.size_bytes()};
+}
+
+template <typename T,
+          size_t X,
+          typename = std::enable_if_t<!std::is_const<T>::value>>
+span<std::byte, (X == dynamic_extent ? dynamic_extent : sizeof(T) * X)>
+as_writable_bytes(span<T, X> s) noexcept {
+  return {reinterpret_cast<std::byte*>(s.data()), s.size_bytes()};
+}
+
+// Type-deducing helpers for constructing a span.
+// Pigweed: Instead of a make_span function, provide the deduction guides
+//     specified in the C++20 standard.
+#ifdef __cpp_deduction_guides
+
+template <class T, std::size_t N>
+span(T (&)[N]) -> span<T, N>;
+
+template <class T, std::size_t N>
+span(std::array<T, N>&) -> span<T, N>;
+
+template <class T, std::size_t N>
+span(const std::array<T, N>&) -> span<const T, N>;
+
+namespace pw_span_internal {
+
+// Containers can be mutable or const and have mutable or const members. Check
+// the type of the accessed elements to determine which type of span should be
+// created (e.g. span<char> or span<const char>).
+template <typename T>
+using ValueType = std::remove_reference_t<decltype(std::declval<T>()[0])>;
+
+}  // namespace pw_span_internal
+
+// This diverges a little from the standard, which uses std::ranges.
+template <class Container>
+span(Container&) -> span<pw_span_internal::ValueType<Container>>;
+
+template <class Container>
+span(const Container&) -> span<pw_span_internal::ValueType<const Container>>;
+
+#endif  // __cpp_deduction_guides
+
+}  // namespace std
+
+#undef _PW_SPAN_ASSERT
diff --git a/pw_span/public/pw_span/span.h b/pw_span/public/pw_span/span.h
index 8aa270d..98e7acf 100644
--- a/pw_span/public/pw_span/span.h
+++ b/pw_span/public/pw_span/span.h
@@ -12,28 +12,13 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-// pw::span is a stand-in for C++20's std::span.
+// pw::span is DEPRECATED. Instead of using pw::span from pw_span/span.h, use
+// std::span from <span>. pw_span/span.h and pw::span will be removed once code
+// has been migrated to std::span.
 //
-// A span is a non-owning array view class. It refers to an external array by
-// storing a pointer and length. Unlike std::array, the size does not have to be
-// a template parameter, so this class can be used to without stating its size.
-//
-// This file a modified version of base::span from Chromium:
-//   https://chromium.googlesource.com/chromium/src/+/d93ae920e4309682deb9352a4637cfc2941c1d1f/base/containers/span.h
-//
-// In order to minimize changes from the original, this file does NOT fully
-// adhere to Pigweed's style guide.
-//
-// A few changes were made to the Chromium version of span. These include:
-//   - Use std::data and std::size instead of base::* versions.
-//   - Rename base namespace to pw.
-//   - Rename internal namespace to span_internal.
-//   - Remove uses of checked_iterators.h and CHECK.
-//   - Replace make_span functions with C++17 class template deduction guides.
-//   - Use std::byte instead of uint8_t for compatibility with std::span.
-//
-// Eventually, when C++20 is widely supported, this class will be replaced with
-// std::span.
+// This code is a copy of the std::span code in pw_span/internal/span.h.
+// pw::span cannot be an alias of std::span because class template argument
+// deduction does not work with aliases.
 #pragma once
 
 #include <algorithm>
@@ -234,7 +219,7 @@
 
 // [span], class template span
 template <typename T, size_t Extent>
-class span : public span_internal::ExtentStorage<Extent> {
+class /* [[deprecated]] */ span : public span_internal::ExtentStorage<Extent> {
  private:
   using ExtentStorage = span_internal::ExtentStorage<Extent>;
 
diff --git a/pw_span/public_overrides/span b/pw_span/public_overrides/span
new file mode 100644
index 0000000..7991e33
--- /dev/null
+++ b/pw_span/public_overrides/span
@@ -0,0 +1,28 @@
+// Copyright 2020 The Pigweed Authors
+//
+// 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
+
+#if __has_include(<version>)
+#include <version>
+#endif  // __has_include(<version>)
+
+#ifdef __cpp_lib_span  // C++ library feature test macro, provided by <version>.
+
+#include_next <span>
+
+#else
+
+#include "pw_span/internal/span.h"
+
+#endif  // __cpp_lib_span
diff --git a/pw_span/pw_span_test.cc b/pw_span/pw_span_test.cc
new file mode 100644
index 0000000..00a1adf
--- /dev/null
+++ b/pw_span/pw_span_test.cc
@@ -0,0 +1,1681 @@
+// Copyright 2020 The Pigweed Authors
+//
+// 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.
+
+// This file is a copy of the tests for std::span. It tests pw::span, which is a
+// temporary copy of std::span for compatibility purposes. The pw::span class,
+// and this test, will be deleted as soon as projects fully migrate to
+// std::span.
+#include <algorithm>
+#include <cstdint>
+#include <memory>
+#include <span>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "pw_span/span.h"
+
+// Pigweed: gMock matchers are not yet supported.
+#if 0
+using ::testing::ElementsAre;
+using ::testing::Eq;
+using ::testing::Pointwise;
+#endif  // 0
+
+namespace pw {
+
+namespace {
+
+// constexpr implementation of std::equal's 4 argument overload.
+template <class InputIterator1, class InputIterator2>
+constexpr bool constexpr_equal(InputIterator1 first1,
+                               InputIterator1 last1,
+                               InputIterator2 first2,
+                               InputIterator2 last2) {
+  for (; first1 != last1 && first2 != last2; ++first1, ++first2) {
+    if (*first1 != *first2)
+      return false;
+  }
+
+  return first1 == last1 && first2 == last2;
+}
+
+}  // namespace
+
+// TODO(hepler): Remove these tests after eliminating pw::span.
+TEST(StdSpanCompatibility, ConstructFromPwSpanToStdSpan) {
+  char array[] = {'a', 'b', 'c', 'd', '\0'};
+
+  ::pw::span pw_span(array);
+  std::span std_span(pw_span);
+
+  std_span[0] = '!';
+  EXPECT_STREQ(std_span.data(), "!bcd");
+
+  EXPECT_EQ(pw_span.data(), std_span.data());
+  EXPECT_EQ(pw_span.size(), std_span.size());
+}
+
+TEST(StdSpanCompatibility, ConstructFromStdSpanToPwSpan) {
+  char array[] = {'a', 'b', 'c', 'd', '\0'};
+
+  std::span std_span(array);
+  ::pw::span pw_span(std_span);
+
+  pw_span[0] = '!';
+  EXPECT_STREQ(pw_span.data(), "!bcd");
+
+  EXPECT_EQ(pw_span.data(), std_span.data());
+  EXPECT_EQ(pw_span.size(), std_span.size());
+}
+
+TEST(StdSpanCompatibility, AssignFromPwSpanToStdSpan) {
+  char array[] = {'a', 'b', 'c', 'd', '\0'};
+
+  auto pw_span = ::pw::span(array);
+  std::span std_span = pw_span;
+
+  std_span[0] = '!';
+  EXPECT_STREQ(std_span.data(), "!bcd");
+
+  EXPECT_EQ(pw_span.data(), std_span.data());
+  EXPECT_EQ(pw_span.size(), std_span.size());
+}
+
+TEST(StdSpanCompatibility, AssignFromStdSpanToPwSpan) {
+  char array[] = {'a', 'b', 'c', 'd', '\0'};
+
+  auto std_span = std::span(array);
+  ::pw::span pw_span = std_span;
+
+  pw_span[0] = '!';
+  EXPECT_STREQ(pw_span.data(), "!bcd");
+
+  EXPECT_EQ(pw_span.data(), std_span.data());
+  EXPECT_EQ(pw_span.size(), std_span.size());
+}
+
+TEST(SpanTest, DeductionGuides_MutableArray) {
+  char array[] = {'a', 'b', 'c', 'd', '\0'};
+
+  auto the_span = span(array);
+  static_assert(the_span.extent == 5u);
+  static_assert(the_span.size() == 5u);
+
+  the_span[0] = '!';
+  EXPECT_STREQ(the_span.data(), "!bcd");
+}
+
+TEST(SpanTest, DeductionGuides_ConstArray) {
+  static constexpr char array[] = {'a', 'b', 'c', 'd', '\0'};
+
+  constexpr auto the_span = span(array);
+  static_assert(the_span.extent == 5u);
+  static_assert(the_span.size() == 5u);
+
+  EXPECT_STREQ(the_span.data(), "abcd");
+}
+
+TEST(SpanTest, DeductionGuides_MutableStdArray) {
+  std::array<char, 5> array{'a', 'b', 'c', 'd'};
+
+  auto the_span = span(array);
+  static_assert(the_span.extent == 5u);
+  static_assert(the_span.size() == 5u);
+
+  the_span[0] = '?';
+  EXPECT_STREQ(the_span.data(), "?bcd");
+}
+
+TEST(SpanTest, DeductionGuides_ConstStdArray) {
+  static constexpr std::array<char, 5> array{'a', 'b', 'c', 'd'};
+
+  constexpr auto the_span = span(array);
+  static_assert(the_span.extent == 5u);
+  static_assert(the_span.size() == 5u);
+
+  EXPECT_STREQ(the_span.data(), "abcd");
+}
+
+TEST(SpanTest, DeductionGuides_MutableContainerWithConstElements) {
+  std::string_view string("Hello");
+  auto the_span = span(string);
+  static_assert(the_span.extent == dynamic_extent);
+
+  EXPECT_STREQ("Hello", the_span.data());
+  EXPECT_EQ(5u, the_span.size());
+}
+
+TEST(SpanTest, DeductionGuides_MutableContainerWithMutableElements) {
+  std::string string("Hello");
+  auto the_span = span(string);
+  static_assert(the_span.extent == dynamic_extent);
+
+  EXPECT_EQ(5u, the_span.size());
+  the_span[1] = 'a';
+  EXPECT_STREQ(the_span.data(), string.data());
+  EXPECT_STREQ("Hallo", the_span.data());
+}
+
+class MutableStringView {
+ public:
+  using element_type = char;
+  using value_type = char;
+  using size_type = size_t;
+  using difference_type = ptrdiff_t;
+  using pointer = char*;
+  using reference = char&;
+  using iterator = char*;
+  using const_iterator = const char*;
+  using reverse_iterator = std::reverse_iterator<iterator>;
+  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+  MutableStringView(char* str) : data_(str, std::strlen(str)) {}
+
+  char& operator[](size_type index) const { return data_[index]; }
+  pointer data() const { return data_.data(); }
+  size_type size() const { return data_.size(); }
+  iterator begin() const { return data_.begin(); }
+  iterator end() const { return data_.end(); }
+
+ private:
+  span<char> data_;
+};
+
+TEST(SpanTest, DeductionGuides_ConstContainerWithMutableElements) {
+  char data[] = "54321";
+  MutableStringView view(data);
+
+  auto the_span = span(view);
+  static_assert(the_span.extent == dynamic_extent);
+
+  EXPECT_EQ(5u, the_span.size());
+  view[2] = '?';
+  EXPECT_STREQ("54?21", the_span.data());
+  EXPECT_STREQ("54?21", data);
+}
+
+TEST(SpanTest, DeductionGuides_ConstContainerWithMutableValueType) {
+  const std::string string("Hello");
+  auto the_span = span(string);
+  static_assert(the_span.extent == dynamic_extent);
+
+  EXPECT_EQ(5u, the_span.size());
+  EXPECT_STREQ("Hello", the_span.data());
+}
+
+TEST(SpanTest, DeductionGuides_ConstContainerWithConstElements) {
+  const std::string_view string("Hello");
+  auto the_span = span(string);
+  static_assert(the_span.extent == dynamic_extent);
+
+  EXPECT_EQ(5u, the_span.size());
+  EXPECT_STREQ("Hello", the_span.data());
+}
+
+TEST(SpanTest, DeductionGuides_FromTemporary_ContainerWithConstElements) {
+  auto the_span = span(std::string_view("Hello"));
+  static_assert(the_span.extent == dynamic_extent);
+
+  EXPECT_EQ(5u, the_span.size());
+  EXPECT_STREQ("Hello", the_span.data());
+}
+
+TEST(SpanTest, DeductionGuides_FromReference) {
+  std::array<int, 5> array{1, 3, 5, 7, 9};
+  std::array<int, 5>& array_ref = array;
+
+  auto the_span = span(array_ref);
+  static_assert(the_span.extent == 5);
+
+  for (unsigned i = 0; i < array.size(); ++i) {
+    ASSERT_EQ(array[i], the_span[i]);
+  }
+}
+
+TEST(SpanTest, DeductionGuides_FromConstReference) {
+  std::string_view string = "yo!";
+  const std::string_view& string_ref = string;
+
+  auto the_span = span(string_ref);
+  static_assert(the_span.extent == dynamic_extent);
+
+  EXPECT_EQ(string, the_span.data());
+}
+
+TEST(SpanTest, DefaultConstructor) {
+  span<int> dynamic_span;
+  EXPECT_EQ(nullptr, dynamic_span.data());
+  EXPECT_EQ(0u, dynamic_span.size());
+
+  constexpr span<int, 0> static_span;
+  static_assert(nullptr == static_span.data(), "");
+  static_assert(static_span.empty(), "");
+}
+
+TEST(SpanTest, ConstructFromDataAndSize) {
+  constexpr span<int> empty_span(nullptr, 0);
+  EXPECT_TRUE(empty_span.empty());
+  EXPECT_EQ(nullptr, empty_span.data());
+
+  std::vector<int> vector = {1, 1, 2, 3, 5, 8};
+
+  span<int> dynamic_span(vector.data(), vector.size());
+  EXPECT_EQ(vector.data(), dynamic_span.data());
+  EXPECT_EQ(vector.size(), dynamic_span.size());
+
+  for (size_t i = 0; i < dynamic_span.size(); ++i)
+    EXPECT_EQ(vector[i], dynamic_span[i]);
+
+  span<int, 6> static_span(vector.data(), vector.size());
+  EXPECT_EQ(vector.data(), static_span.data());
+  EXPECT_EQ(vector.size(), static_span.size());
+
+  for (size_t i = 0; i < static_span.size(); ++i)
+    EXPECT_EQ(vector[i], static_span[i]);
+}
+
+TEST(SpanTest, ConstructFromPointerPair) {
+  constexpr span<int> empty_span(nullptr, nullptr);
+  EXPECT_TRUE(empty_span.empty());
+  EXPECT_EQ(nullptr, empty_span.data());
+
+  std::vector<int> vector = {1, 1, 2, 3, 5, 8};
+
+  span<int> dynamic_span(vector.data(), vector.data() + vector.size() / 2);
+  EXPECT_EQ(vector.data(), dynamic_span.data());
+  EXPECT_EQ(vector.size() / 2, dynamic_span.size());
+
+  for (size_t i = 0; i < dynamic_span.size(); ++i)
+    EXPECT_EQ(vector[i], dynamic_span[i]);
+
+  span<int, 3> static_span(vector.data(), vector.data() + vector.size() / 2);
+  EXPECT_EQ(vector.data(), static_span.data());
+  EXPECT_EQ(vector.size() / 2, static_span.size());
+
+  for (size_t i = 0; i < static_span.size(); ++i)
+    EXPECT_EQ(vector[i], static_span[i]);
+}
+
+TEST(SpanTest, AllowedConversionsFromStdArray) {
+  // In the following assertions we use std::is_convertible_v<From, To>, which
+  // for non-void types is equivalent to checking whether the following
+  // expression is well-formed:
+  //
+  // T obj = std::declval<From>();
+  //
+  // In particular we are checking whether From is implicitly convertible to To,
+  // which also implies that To is explicitly constructible from From.
+  static_assert(
+      std::is_convertible<std::array<int, 3>&, span<int>>::value,
+      "Error: l-value reference to std::array<int> should be convertible to "
+      "span<int> with dynamic extent.");
+  static_assert(
+      std::is_convertible<std::array<int, 3>&, span<int, 3>>::value,
+      "Error: l-value reference to std::array<int> should be convertible to "
+      "span<int> with the same static extent.");
+  static_assert(
+      std::is_convertible<std::array<int, 3>&, span<const int>>::value,
+      "Error: l-value reference to std::array<int> should be convertible to "
+      "span<const int> with dynamic extent.");
+  static_assert(
+      std::is_convertible<std::array<int, 3>&, span<const int, 3>>::value,
+      "Error: l-value reference to std::array<int> should be convertible to "
+      "span<const int> with the same static extent.");
+  static_assert(
+      std::is_convertible<const std::array<int, 3>&, span<const int>>::value,
+      "Error: const l-value reference to std::array<int> should be "
+      "convertible to span<const int> with dynamic extent.");
+  static_assert(
+      std::is_convertible<const std::array<int, 3>&, span<const int, 3>>::value,
+      "Error: const l-value reference to std::array<int> should be convertible "
+      "to span<const int> with the same static extent.");
+  static_assert(
+      std::is_convertible<std::array<const int, 3>&, span<const int>>::value,
+      "Error: l-value reference to std::array<const int> should be "
+      "convertible to span<const int> with dynamic extent.");
+  static_assert(
+      std::is_convertible<std::array<const int, 3>&, span<const int, 3>>::value,
+      "Error: l-value reference to std::array<const int> should be convertible "
+      "to span<const int> with the same static extent.");
+  static_assert(
+      std::is_convertible<const std::array<const int, 3>&,
+                          span<const int>>::value,
+      "Error: const l-value reference to std::array<const int> should be "
+      "convertible to span<const int> with dynamic extent.");
+  static_assert(
+      std::is_convertible<const std::array<const int, 3>&,
+                          span<const int, 3>>::value,
+      "Error: const l-value reference to std::array<const int> should be "
+      "convertible to span<const int> with the same static extent.");
+}
+
+TEST(SpanTest, DisallowedConstructionsFromStdArray) {
+  // In the following assertions we use !std::is_constructible_v<T, Args>, which
+  // is equivalent to checking whether the following expression is malformed:
+  //
+  // T obj(std::declval<Args>()...);
+  //
+  // In particular we are checking that T is not explicitly constructible from
+  // Args, which also implies that T is not implicitly constructible from Args
+  // as well.
+  static_assert(
+      !std::is_constructible<span<int>, const std::array<int, 3>&>::value,
+      "Error: span<int> with dynamic extent should not be constructible "
+      "from const l-value reference to std::array<int>");
+
+  static_assert(
+      !std::is_constructible<span<int>, std::array<const int, 3>&>::value,
+      "Error: span<int> with dynamic extent should not be constructible "
+      "from l-value reference to std::array<const int>");
+
+  static_assert(
+      !std::is_constructible<span<int>, const std::array<const int, 3>&>::value,
+      "Error: span<int> with dynamic extent should not be constructible "
+      "const from l-value reference to std::array<const int>");
+
+  static_assert(
+      !std::is_constructible<span<int, 2>, std::array<int, 3>&>::value,
+      "Error: span<int> with static extent should not be constructible "
+      "from l-value reference to std::array<int> with different extent");
+
+  static_assert(
+      !std::is_constructible<span<int, 4>, std::array<int, 3>&>::value,
+      "Error: span<int> with dynamic extent should not be constructible "
+      "from l-value reference to std::array<int> with different extent");
+
+  static_assert(
+      !std::is_constructible<span<int>, std::array<bool, 3>&>::value,
+      "Error: span<int> with dynamic extent should not be constructible "
+      "from l-value reference to std::array<bool>");
+}
+
+TEST(SpanTest, ConstructFromConstexprArray) {
+  static constexpr int kArray[] = {5, 4, 3, 2, 1};
+
+  constexpr span<const int> dynamic_span(kArray);
+  static_assert(kArray == dynamic_span.data(), "");
+  static_assert(std::size(kArray) == dynamic_span.size(), "");
+
+  static_assert(kArray[0] == dynamic_span[0], "");
+  static_assert(kArray[1] == dynamic_span[1], "");
+  static_assert(kArray[2] == dynamic_span[2], "");
+  static_assert(kArray[3] == dynamic_span[3], "");
+  static_assert(kArray[4] == dynamic_span[4], "");
+
+  constexpr span<const int, std::size(kArray)> static_span(kArray);
+  static_assert(kArray == static_span.data(), "");
+  static_assert(std::size(kArray) == static_span.size(), "");
+
+  static_assert(kArray[0] == static_span[0], "");
+  static_assert(kArray[1] == static_span[1], "");
+  static_assert(kArray[2] == static_span[2], "");
+  static_assert(kArray[3] == static_span[3], "");
+  static_assert(kArray[4] == static_span[4], "");
+}
+
+TEST(SpanTest, ConstructFromArray) {
+  int array[] = {5, 4, 3, 2, 1};
+
+  span<const int> const_span(array);
+  EXPECT_EQ(array, const_span.data());
+  EXPECT_EQ(std::size(array), const_span.size());
+  for (size_t i = 0; i < const_span.size(); ++i)
+    EXPECT_EQ(array[i], const_span[i]);
+
+  span<int> dynamic_span(array);
+  EXPECT_EQ(array, dynamic_span.data());
+  EXPECT_EQ(std::size(array), dynamic_span.size());
+  for (size_t i = 0; i < dynamic_span.size(); ++i)
+    EXPECT_EQ(array[i], dynamic_span[i]);
+
+  span<int, std::size(array)> static_span(array);
+  EXPECT_EQ(array, static_span.data());
+  EXPECT_EQ(std::size(array), static_span.size());
+  for (size_t i = 0; i < static_span.size(); ++i)
+    EXPECT_EQ(array[i], static_span[i]);
+}
+
+TEST(SpanTest, ConstructFromStdArray) {
+  // Note: Constructing a constexpr span from a constexpr std::array does not
+  // work prior to C++17 due to non-constexpr std::array::data.
+  std::array<int, 5> array = {{5, 4, 3, 2, 1}};
+
+  span<const int> const_span(array);
+  EXPECT_EQ(array.data(), const_span.data());
+  EXPECT_EQ(array.size(), const_span.size());
+  for (size_t i = 0; i < const_span.size(); ++i)
+    EXPECT_EQ(array[i], const_span[i]);
+
+  span<int> dynamic_span(array);
+  EXPECT_EQ(array.data(), dynamic_span.data());
+  EXPECT_EQ(array.size(), dynamic_span.size());
+  for (size_t i = 0; i < dynamic_span.size(); ++i)
+    EXPECT_EQ(array[i], dynamic_span[i]);
+
+  span<int, std::size(array)> static_span(array);
+  EXPECT_EQ(array.data(), static_span.data());
+  EXPECT_EQ(array.size(), static_span.size());
+  for (size_t i = 0; i < static_span.size(); ++i)
+    EXPECT_EQ(array[i], static_span[i]);
+}
+
+TEST(SpanTest, ConstructFromInitializerList) {
+  std::initializer_list<int> il = {1, 1, 2, 3, 5, 8};
+
+  span<const int> const_span(il);
+  EXPECT_EQ(il.begin(), const_span.data());
+  EXPECT_EQ(il.size(), const_span.size());
+
+  for (size_t i = 0; i < const_span.size(); ++i)
+    EXPECT_EQ(il.begin()[i], const_span[i]);
+
+  span<const int, 6> static_span(il.begin(), il.end());
+  EXPECT_EQ(il.begin(), static_span.data());
+  EXPECT_EQ(il.size(), static_span.size());
+
+  for (size_t i = 0; i < static_span.size(); ++i)
+    EXPECT_EQ(il.begin()[i], static_span[i]);
+}
+
+TEST(SpanTest, ConstructFromStdString) {
+  std::string str = "foobar";
+
+  span<const char> const_span(str);
+  EXPECT_EQ(str.data(), const_span.data());
+  EXPECT_EQ(str.size(), const_span.size());
+
+  for (size_t i = 0; i < const_span.size(); ++i)
+    EXPECT_EQ(str[i], const_span[i]);
+
+  span<char> dynamic_span(str);
+  EXPECT_EQ(str.data(), dynamic_span.data());
+  EXPECT_EQ(str.size(), dynamic_span.size());
+
+  for (size_t i = 0; i < dynamic_span.size(); ++i)
+    EXPECT_EQ(str[i], dynamic_span[i]);
+
+  span<char, 6> static_span(data(str), str.size());
+  EXPECT_EQ(str.data(), static_span.data());
+  EXPECT_EQ(str.size(), static_span.size());
+
+  for (size_t i = 0; i < static_span.size(); ++i)
+    EXPECT_EQ(str[i], static_span[i]);
+}
+
+TEST(SpanTest, ConstructFromConstContainer) {
+  const std::vector<int> vector = {1, 1, 2, 3, 5, 8};
+
+  span<const int> const_span(vector);
+  EXPECT_EQ(vector.data(), const_span.data());
+  EXPECT_EQ(vector.size(), const_span.size());
+
+  for (size_t i = 0; i < const_span.size(); ++i)
+    EXPECT_EQ(vector[i], const_span[i]);
+
+  span<const int, 6> static_span(vector.data(), vector.size());
+  EXPECT_EQ(vector.data(), static_span.data());
+  EXPECT_EQ(vector.size(), static_span.size());
+
+  for (size_t i = 0; i < static_span.size(); ++i)
+    EXPECT_EQ(vector[i], static_span[i]);
+}
+
+TEST(SpanTest, ConstructFromContainer) {
+  std::vector<int> vector = {1, 1, 2, 3, 5, 8};
+
+  span<const int> const_span(vector);
+  EXPECT_EQ(vector.data(), const_span.data());
+  EXPECT_EQ(vector.size(), const_span.size());
+
+  for (size_t i = 0; i < const_span.size(); ++i)
+    EXPECT_EQ(vector[i], const_span[i]);
+
+  span<int> dynamic_span(vector);
+  EXPECT_EQ(vector.data(), dynamic_span.data());
+  EXPECT_EQ(vector.size(), dynamic_span.size());
+
+  for (size_t i = 0; i < dynamic_span.size(); ++i)
+    EXPECT_EQ(vector[i], dynamic_span[i]);
+
+  span<int, 6> static_span(vector.data(), vector.size());
+  EXPECT_EQ(vector.data(), static_span.data());
+  EXPECT_EQ(vector.size(), static_span.size());
+
+  for (size_t i = 0; i < static_span.size(); ++i)
+    EXPECT_EQ(vector[i], static_span[i]);
+}
+
+#if 0
+
+// Pigweed: gMock matchers are not yet supported.
+TEST(SpanTest, ConvertNonConstIntegralToConst) {
+  std::vector<int> vector = {1, 1, 2, 3, 5, 8};
+
+  span<int> int_span(vector.data(), vector.size());
+  span<const int> const_span(int_span);
+  EXPECT_EQ(int_span.size(), const_span.size());
+
+  EXPECT_THAT(const_span, Pointwise(Eq(), int_span));
+
+  span<int, 6> static_int_span(vector.data(), vector.size());
+  span<const int, 6> static_const_span(static_int_span);
+  EXPECT_THAT(static_const_span, Pointwise(Eq(), static_int_span));
+}
+
+// Pigweed: gMock matchers are not yet supported.
+TEST(SpanTest, ConvertNonConstPointerToConst) {
+  auto a = std::make_unique<int>(11);
+  auto b = std::make_unique<int>(22);
+  auto c = std::make_unique<int>(33);
+  std::vector<int*> vector = {a.get(), b.get(), c.get()};
+
+  span<int*> non_const_pointer_span(vector);
+  EXPECT_THAT(non_const_pointer_span, Pointwise(Eq(), vector));
+  span<int* const> const_pointer_span(non_const_pointer_span);
+  EXPECT_THAT(const_pointer_span, Pointwise(Eq(), non_const_pointer_span));
+  // Note: no test for conversion from span<int> to span<const int*>, since that
+  // would imply a conversion from int** to const int**, which is unsafe.
+  //
+  // Note: no test for conversion from span<int*> to span<const int* const>,
+  // due to CWG Defect 330:
+  // http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#330
+
+  span<int*, 3> static_non_const_pointer_span(vector.data(), vector.size());
+  EXPECT_THAT(static_non_const_pointer_span, Pointwise(Eq(), vector));
+  span<int* const, 3> static_const_pointer_span(static_non_const_pointer_span);
+  EXPECT_THAT(static_const_pointer_span,
+              Pointwise(Eq(), static_non_const_pointer_span));
+}
+
+// Pigweed: This test does not work on platforms where int32_t is long int.
+TEST(SpanTest, ConvertBetweenEquivalentTypes) {
+  std::vector<int32_t> vector = {2, 4, 8, 16, 32};
+
+  span<int32_t> int32_t_span(vector);
+  span<int> converted_span(int32_t_span);
+  EXPECT_EQ(int32_t_span.data(), converted_span.data());
+  EXPECT_EQ(int32_t_span.size(), converted_span.size());
+
+  span<int32_t, 5> static_int32_t_span(vector.data(), vector.size());
+  span<int, 5> static_converted_span(static_int32_t_span);
+  EXPECT_EQ(static_int32_t_span.data(), static_converted_span.data());
+  EXPECT_EQ(static_int32_t_span.size(), static_converted_span.size());
+}
+
+#endif  // 0
+
+TEST(SpanTest, TemplatedFirst) {
+  static constexpr int array[] = {1, 2, 3};
+  constexpr span<const int, 3> span(array);
+
+  {
+    constexpr auto subspan = span.first<0>();
+    static_assert(span.data() == subspan.data(), "");
+    static_assert(subspan.empty(), "");
+    static_assert(0u == decltype(subspan)::extent, "");
+  }
+
+  {
+    constexpr auto subspan = span.first<1>();
+    static_assert(span.data() == subspan.data(), "");
+    static_assert(1u == subspan.size(), "");
+    static_assert(1u == decltype(subspan)::extent, "");
+    static_assert(1 == subspan[0], "");
+  }
+
+  {
+    constexpr auto subspan = span.first<2>();
+    static_assert(span.data() == subspan.data(), "");
+    static_assert(2u == subspan.size(), "");
+    static_assert(2u == decltype(subspan)::extent, "");
+    static_assert(1 == subspan[0], "");
+    static_assert(2 == subspan[1], "");
+  }
+
+  {
+    constexpr auto subspan = span.first<3>();
+    static_assert(span.data() == subspan.data(), "");
+    static_assert(3u == subspan.size(), "");
+    static_assert(3u == decltype(subspan)::extent, "");
+    static_assert(1 == subspan[0], "");
+    static_assert(2 == subspan[1], "");
+    static_assert(3 == subspan[2], "");
+  }
+}
+
+TEST(SpanTest, TemplatedLast) {
+  static constexpr int array[] = {1, 2, 3};
+  constexpr span<const int, 3> span(array);
+
+  {
+    constexpr auto subspan = span.last<0>();
+    static_assert(span.data() + 3 == subspan.data(), "");
+    static_assert(subspan.empty(), "");
+    static_assert(0u == decltype(subspan)::extent, "");
+  }
+
+  {
+    constexpr auto subspan = span.last<1>();
+    static_assert(span.data() + 2 == subspan.data(), "");
+    static_assert(1u == subspan.size(), "");
+    static_assert(1u == decltype(subspan)::extent, "");
+    static_assert(3 == subspan[0], "");
+  }
+
+  {
+    constexpr auto subspan = span.last<2>();
+    static_assert(span.data() + 1 == subspan.data(), "");
+    static_assert(2u == subspan.size(), "");
+    static_assert(2u == decltype(subspan)::extent, "");
+    static_assert(2 == subspan[0], "");
+    static_assert(3 == subspan[1], "");
+  }
+
+  {
+    constexpr auto subspan = span.last<3>();
+    static_assert(span.data() == subspan.data(), "");
+    static_assert(3u == subspan.size(), "");
+    static_assert(3u == decltype(subspan)::extent, "");
+    static_assert(1 == subspan[0], "");
+    static_assert(2 == subspan[1], "");
+    static_assert(3 == subspan[2], "");
+  }
+}
+
+TEST(SpanTest, TemplatedSubspan) {
+  static constexpr int array[] = {1, 2, 3};
+  constexpr span<const int, 3> span(array);
+
+  {
+    constexpr auto subspan = span.subspan<0>();
+    static_assert(span.data() == subspan.data(), "");
+    static_assert(3u == subspan.size(), "");
+    static_assert(3u == decltype(subspan)::extent, "");
+    static_assert(1 == subspan[0], "");
+    static_assert(2 == subspan[1], "");
+    static_assert(3 == subspan[2], "");
+  }
+
+  {
+    constexpr auto subspan = span.subspan<1>();
+    static_assert(span.data() + 1 == subspan.data(), "");
+    static_assert(2u == subspan.size(), "");
+    static_assert(2u == decltype(subspan)::extent, "");
+    static_assert(2 == subspan[0], "");
+    static_assert(3 == subspan[1], "");
+  }
+
+  {
+    constexpr auto subspan = span.subspan<2>();
+    static_assert(span.data() + 2 == subspan.data(), "");
+    static_assert(1u == subspan.size(), "");
+    static_assert(1u == decltype(subspan)::extent, "");
+    static_assert(3 == subspan[0], "");
+  }
+
+  {
+    constexpr auto subspan = span.subspan<3>();
+    static_assert(span.data() + 3 == subspan.data(), "");
+    static_assert(subspan.empty(), "");
+    static_assert(0u == decltype(subspan)::extent, "");
+  }
+
+  {
+    constexpr auto subspan = span.subspan<0, 0>();
+    static_assert(span.data() == subspan.data(), "");
+    static_assert(subspan.empty(), "");
+    static_assert(0u == decltype(subspan)::extent, "");
+  }
+
+  {
+    constexpr auto subspan = span.subspan<1, 0>();
+    static_assert(span.data() + 1 == subspan.data(), "");
+    static_assert(subspan.empty(), "");
+    static_assert(0u == decltype(subspan)::extent, "");
+  }
+
+  {
+    constexpr auto subspan = span.subspan<2, 0>();
+    static_assert(span.data() + 2 == subspan.data(), "");
+    static_assert(subspan.empty(), "");
+    static_assert(0u == decltype(subspan)::extent, "");
+  }
+
+  {
+    constexpr auto subspan = span.subspan<0, 1>();
+    static_assert(span.data() == subspan.data(), "");
+    static_assert(1u == subspan.size(), "");
+    static_assert(1u == decltype(subspan)::extent, "");
+    static_assert(1 == subspan[0], "");
+  }
+
+  {
+    constexpr auto subspan = span.subspan<1, 1>();
+    static_assert(span.data() + 1 == subspan.data(), "");
+    static_assert(1u == subspan.size(), "");
+    static_assert(1u == decltype(subspan)::extent, "");
+    static_assert(2 == subspan[0], "");
+  }
+
+  {
+    constexpr auto subspan = span.subspan<2, 1>();
+    static_assert(span.data() + 2 == subspan.data(), "");
+    static_assert(1u == subspan.size(), "");
+    static_assert(1u == decltype(subspan)::extent, "");
+    static_assert(3 == subspan[0], "");
+  }
+
+  {
+    constexpr auto subspan = span.subspan<0, 2>();
+    static_assert(span.data() == subspan.data(), "");
+    static_assert(2u == subspan.size(), "");
+    static_assert(2u == decltype(subspan)::extent, "");
+    static_assert(1 == subspan[0], "");
+    static_assert(2 == subspan[1], "");
+  }
+
+  {
+    constexpr auto subspan = span.subspan<1, 2>();
+    static_assert(span.data() + 1 == subspan.data(), "");
+    static_assert(2u == subspan.size(), "");
+    static_assert(2u == decltype(subspan)::extent, "");
+    static_assert(2 == subspan[0], "");
+    static_assert(3 == subspan[1], "");
+  }
+
+  {
+    constexpr auto subspan = span.subspan<0, 3>();
+    static_assert(span.data() == subspan.data(), "");
+    static_assert(3u == subspan.size(), "");
+    static_assert(3u == decltype(subspan)::extent, "");
+    static_assert(1 == subspan[0], "");
+    static_assert(2 == subspan[1], "");
+    static_assert(3 == subspan[2], "");
+  }
+}
+
+TEST(SpanTest, SubscriptedBeginIterator) {
+  int array[] = {1, 2, 3};
+  span<const int> const_span(array);
+  for (size_t i = 0; i < const_span.size(); ++i)
+    EXPECT_EQ(array[i], const_span.begin()[i]);
+
+  span<int> mutable_span(array);
+  for (size_t i = 0; i < mutable_span.size(); ++i)
+    EXPECT_EQ(array[i], mutable_span.begin()[i]);
+}
+
+TEST(SpanTest, TemplatedFirstOnDynamicSpan) {
+  int array[] = {1, 2, 3};
+  span<const int> span(array);
+
+  {
+    auto subspan = span.first<0>();
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(0u, subspan.size());
+    static_assert(0u == decltype(subspan)::extent, "");
+  }
+
+  {
+    auto subspan = span.first<1>();
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(1u, subspan.size());
+    static_assert(1u == decltype(subspan)::extent, "");
+    EXPECT_EQ(1, subspan[0]);
+  }
+
+  {
+    auto subspan = span.first<2>();
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(2u, subspan.size());
+    static_assert(2u == decltype(subspan)::extent, "");
+    EXPECT_EQ(1, subspan[0]);
+    EXPECT_EQ(2, subspan[1]);
+  }
+
+  {
+    auto subspan = span.first<3>();
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(3u, subspan.size());
+    static_assert(3u == decltype(subspan)::extent, "");
+    EXPECT_EQ(1, subspan[0]);
+    EXPECT_EQ(2, subspan[1]);
+    EXPECT_EQ(3, subspan[2]);
+  }
+}
+
+TEST(SpanTest, TemplatedLastOnDynamicSpan) {
+  int array[] = {1, 2, 3};
+  span<int> span(array);
+
+  {
+    auto subspan = span.last<0>();
+    EXPECT_EQ(span.data() + 3, subspan.data());
+    EXPECT_EQ(0u, subspan.size());
+    static_assert(0u == decltype(subspan)::extent, "");
+  }
+
+  {
+    auto subspan = span.last<1>();
+    EXPECT_EQ(span.data() + 2, subspan.data());
+    EXPECT_EQ(1u, subspan.size());
+    static_assert(1u == decltype(subspan)::extent, "");
+    EXPECT_EQ(3, subspan[0]);
+  }
+
+  {
+    auto subspan = span.last<2>();
+    EXPECT_EQ(span.data() + 1, subspan.data());
+    EXPECT_EQ(2u, subspan.size());
+    static_assert(2u == decltype(subspan)::extent, "");
+    EXPECT_EQ(2, subspan[0]);
+    EXPECT_EQ(3, subspan[1]);
+  }
+
+  {
+    auto subspan = span.last<3>();
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(3u, subspan.size());
+    static_assert(3u == decltype(subspan)::extent, "");
+    EXPECT_EQ(1, subspan[0]);
+    EXPECT_EQ(2, subspan[1]);
+    EXPECT_EQ(3, subspan[2]);
+  }
+}
+
+TEST(SpanTest, TemplatedSubspanFromDynamicSpan) {
+  int array[] = {1, 2, 3};
+  span<int, 3> span(array);
+
+  {
+    auto subspan = span.subspan<0>();
+    EXPECT_EQ(span.data(), subspan.data());
+    static_assert(3u == decltype(subspan)::extent, "");
+    EXPECT_EQ(3u, subspan.size());
+    EXPECT_EQ(1, subspan[0]);
+    EXPECT_EQ(2, subspan[1]);
+    EXPECT_EQ(3, subspan[2]);
+  }
+
+  {
+    auto subspan = span.subspan<1>();
+    EXPECT_EQ(span.data() + 1, subspan.data());
+    EXPECT_EQ(2u, subspan.size());
+    static_assert(2u == decltype(subspan)::extent, "");
+    EXPECT_EQ(2, subspan[0]);
+    EXPECT_EQ(3, subspan[1]);
+  }
+
+  {
+    auto subspan = span.subspan<2>();
+    EXPECT_EQ(span.data() + 2, subspan.data());
+    EXPECT_EQ(1u, subspan.size());
+    static_assert(1u == decltype(subspan)::extent, "");
+    EXPECT_EQ(3, subspan[0]);
+  }
+
+  {
+    auto subspan = span.subspan<3>();
+    EXPECT_EQ(span.data() + 3, subspan.data());
+    EXPECT_EQ(0u, subspan.size());
+    static_assert(0u == decltype(subspan)::extent, "");
+  }
+
+  {
+    auto subspan = span.subspan<0, 0>();
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(0u, subspan.size());
+    static_assert(0u == decltype(subspan)::extent, "");
+  }
+
+  {
+    auto subspan = span.subspan<1, 0>();
+    EXPECT_EQ(span.data() + 1, subspan.data());
+    EXPECT_EQ(0u, subspan.size());
+    static_assert(0u == decltype(subspan)::extent, "");
+  }
+
+  {
+    auto subspan = span.subspan<2, 0>();
+    EXPECT_EQ(span.data() + 2, subspan.data());
+    EXPECT_EQ(0u, subspan.size());
+    static_assert(0u == decltype(subspan)::extent, "");
+  }
+
+  {
+    auto subspan = span.subspan<0, 1>();
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(1u, subspan.size());
+    static_assert(1u == decltype(subspan)::extent, "");
+    EXPECT_EQ(1, subspan[0]);
+  }
+
+  {
+    auto subspan = span.subspan<1, 1>();
+    EXPECT_EQ(span.data() + 1, subspan.data());
+    EXPECT_EQ(1u, subspan.size());
+    static_assert(1u == decltype(subspan)::extent, "");
+    EXPECT_EQ(2, subspan[0]);
+  }
+
+  {
+    auto subspan = span.subspan<2, 1>();
+    EXPECT_EQ(span.data() + 2, subspan.data());
+    EXPECT_EQ(1u, subspan.size());
+    static_assert(1u == decltype(subspan)::extent, "");
+    EXPECT_EQ(3, subspan[0]);
+  }
+
+  {
+    auto subspan = span.subspan<0, 2>();
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(2u, subspan.size());
+    static_assert(2u == decltype(subspan)::extent, "");
+    EXPECT_EQ(1, subspan[0]);
+    EXPECT_EQ(2, subspan[1]);
+  }
+
+  {
+    auto subspan = span.subspan<1, 2>();
+    EXPECT_EQ(span.data() + 1, subspan.data());
+    EXPECT_EQ(2u, subspan.size());
+    static_assert(2u == decltype(subspan)::extent, "");
+    EXPECT_EQ(2, subspan[0]);
+    EXPECT_EQ(3, subspan[1]);
+  }
+
+  {
+    auto subspan = span.subspan<0, 3>();
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(3u, subspan.size());
+    static_assert(3u == decltype(subspan)::extent, "");
+    EXPECT_EQ(1, subspan[0]);
+    EXPECT_EQ(2, subspan[1]);
+    EXPECT_EQ(3, subspan[2]);
+  }
+}
+
+TEST(SpanTest, First) {
+  int array[] = {1, 2, 3};
+  span<int> span(array);
+
+  {
+    auto subspan = span.first(0);
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(0u, subspan.size());
+  }
+
+  {
+    auto subspan = span.first(1);
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(1u, subspan.size());
+    EXPECT_EQ(1, subspan[0]);
+  }
+
+  {
+    auto subspan = span.first(2);
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(2u, subspan.size());
+    EXPECT_EQ(1, subspan[0]);
+    EXPECT_EQ(2, subspan[1]);
+  }
+
+  {
+    auto subspan = span.first(3);
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(3u, subspan.size());
+    EXPECT_EQ(1, subspan[0]);
+    EXPECT_EQ(2, subspan[1]);
+    EXPECT_EQ(3, subspan[2]);
+  }
+}
+
+TEST(SpanTest, Last) {
+  int array[] = {1, 2, 3};
+  span<int> span(array);
+
+  {
+    auto subspan = span.last(0);
+    EXPECT_EQ(span.data() + 3, subspan.data());
+    EXPECT_EQ(0u, subspan.size());
+  }
+
+  {
+    auto subspan = span.last(1);
+    EXPECT_EQ(span.data() + 2, subspan.data());
+    EXPECT_EQ(1u, subspan.size());
+    EXPECT_EQ(3, subspan[0]);
+  }
+
+  {
+    auto subspan = span.last(2);
+    EXPECT_EQ(span.data() + 1, subspan.data());
+    EXPECT_EQ(2u, subspan.size());
+    EXPECT_EQ(2, subspan[0]);
+    EXPECT_EQ(3, subspan[1]);
+  }
+
+  {
+    auto subspan = span.last(3);
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(3u, subspan.size());
+    EXPECT_EQ(1, subspan[0]);
+    EXPECT_EQ(2, subspan[1]);
+    EXPECT_EQ(3, subspan[2]);
+  }
+}
+
+TEST(SpanTest, Subspan) {
+  int array[] = {1, 2, 3};
+  span<int> span(array);
+
+  {
+    auto subspan = span.subspan(0);
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(3u, subspan.size());
+    EXPECT_EQ(1, subspan[0]);
+    EXPECT_EQ(2, subspan[1]);
+    EXPECT_EQ(3, subspan[2]);
+  }
+
+  {
+    auto subspan = span.subspan(1);
+    EXPECT_EQ(span.data() + 1, subspan.data());
+    EXPECT_EQ(2u, subspan.size());
+    EXPECT_EQ(2, subspan[0]);
+    EXPECT_EQ(3, subspan[1]);
+  }
+
+  {
+    auto subspan = span.subspan(2);
+    EXPECT_EQ(span.data() + 2, subspan.data());
+    EXPECT_EQ(1u, subspan.size());
+    EXPECT_EQ(3, subspan[0]);
+  }
+
+  {
+    auto subspan = span.subspan(3);
+    EXPECT_EQ(span.data() + 3, subspan.data());
+    EXPECT_EQ(0u, subspan.size());
+  }
+
+  {
+    auto subspan = span.subspan(0, 0);
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(0u, subspan.size());
+  }
+
+  {
+    auto subspan = span.subspan(1, 0);
+    EXPECT_EQ(span.data() + 1, subspan.data());
+    EXPECT_EQ(0u, subspan.size());
+  }
+
+  {
+    auto subspan = span.subspan(2, 0);
+    EXPECT_EQ(span.data() + 2, subspan.data());
+    EXPECT_EQ(0u, subspan.size());
+  }
+
+  {
+    auto subspan = span.subspan(0, 1);
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(1u, subspan.size());
+    EXPECT_EQ(1, subspan[0]);
+  }
+
+  {
+    auto subspan = span.subspan(1, 1);
+    EXPECT_EQ(span.data() + 1, subspan.data());
+    EXPECT_EQ(1u, subspan.size());
+    EXPECT_EQ(2, subspan[0]);
+  }
+
+  {
+    auto subspan = span.subspan(2, 1);
+    EXPECT_EQ(span.data() + 2, subspan.data());
+    EXPECT_EQ(1u, subspan.size());
+    EXPECT_EQ(3, subspan[0]);
+  }
+
+  {
+    auto subspan = span.subspan(0, 2);
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(2u, subspan.size());
+    EXPECT_EQ(1, subspan[0]);
+    EXPECT_EQ(2, subspan[1]);
+  }
+
+  {
+    auto subspan = span.subspan(1, 2);
+    EXPECT_EQ(span.data() + 1, subspan.data());
+    EXPECT_EQ(2u, subspan.size());
+    EXPECT_EQ(2, subspan[0]);
+    EXPECT_EQ(3, subspan[1]);
+  }
+
+  {
+    auto subspan = span.subspan(0, 3);
+    EXPECT_EQ(span.data(), subspan.data());
+    EXPECT_EQ(span.size(), subspan.size());
+    EXPECT_EQ(1, subspan[0]);
+    EXPECT_EQ(2, subspan[1]);
+    EXPECT_EQ(3, subspan[2]);
+  }
+}
+
+TEST(SpanTest, Size) {
+  {
+    span<int> span;
+    EXPECT_EQ(0u, span.size());
+  }
+
+  {
+    int array[] = {1, 2, 3};
+    span<int> span(array);
+    EXPECT_EQ(3u, span.size());
+  }
+}
+
+TEST(SpanTest, SizeBytes) {
+  {
+    span<int> span;
+    EXPECT_EQ(0u, span.size_bytes());
+  }
+
+  {
+    int array[] = {1, 2, 3};
+    span<int> span(array);
+    EXPECT_EQ(3u * sizeof(int), span.size_bytes());
+  }
+}
+
+TEST(SpanTest, Empty) {
+  {
+    span<int> span;
+    EXPECT_TRUE(span.empty());
+  }
+
+  {
+    int array[] = {1, 2, 3};
+    span<int> span(array);
+    EXPECT_FALSE(span.empty());
+  }
+}
+
+TEST(SpanTest, OperatorAt) {
+  static constexpr int kArray[] = {1, 6, 1, 8, 0};
+  constexpr span<const int> span(kArray);
+
+  static_assert(&kArray[0] == &span[0],
+                "span[0] does not refer to the same element as kArray[0]");
+  static_assert(&kArray[1] == &span[1],
+                "span[1] does not refer to the same element as kArray[1]");
+  static_assert(&kArray[2] == &span[2],
+                "span[2] does not refer to the same element as kArray[2]");
+  static_assert(&kArray[3] == &span[3],
+                "span[3] does not refer to the same element as kArray[3]");
+  static_assert(&kArray[4] == &span[4],
+                "span[4] does not refer to the same element as kArray[4]");
+}
+
+TEST(SpanTest, Front) {
+  static constexpr int kArray[] = {1, 6, 1, 8, 0};
+  constexpr span<const int> span(kArray);
+  static_assert(&kArray[0] == &span.front(),
+                "span.front() does not refer to the same element as kArray[0]");
+}
+
+TEST(SpanTest, Back) {
+  static constexpr int kArray[] = {1, 6, 1, 8, 0};
+  constexpr span<const int> span(kArray);
+  static_assert(&kArray[4] == &span.back(),
+                "span.back() does not refer to the same element as kArray[4]");
+}
+
+// Pigweed: This test uses gMock features not yet supported in Pigweed.
+#if 0
+TEST(SpanTest, Iterator) {
+  static constexpr int kArray[] = {1, 6, 1, 8, 0};
+  constexpr span<const int> span(kArray);
+
+  std::vector<int> results;
+  for (int i : span)
+    results.emplace_back(i);
+  EXPECT_THAT(results, ElementsAre(1, 6, 1, 8, 0));
+}
+#endif  // 0
+
+TEST(SpanTest, ConstexprIterator) {
+  static constexpr int kArray[] = {1, 6, 1, 8, 0};
+  constexpr span<const int> span(kArray);
+
+  static_assert(
+      constexpr_equal(
+          std::begin(kArray), std::end(kArray), span.begin(), span.end()),
+      "");
+  static_assert(1 == span.begin()[0], "");
+  // Pigweed: These tests assume an iterator object, but Pigweed's span uses a
+  //          simple pointer.
+#if 0
+  static_assert(1 == *(span.begin() += 0), "");
+  static_assert(6 == *(span.begin() += 1), "");
+
+  static_assert(1 == *((span.begin() + 1) -= 1), "");
+  static_assert(6 == *((span.begin() + 1) -= 0), "");
+#endif  // 0
+}
+
+TEST(SpanTest, ReverseIterator) {
+  static constexpr int kArray[] = {1, 6, 1, 8, 0};
+  constexpr span<const int> span(kArray);
+
+  EXPECT_TRUE(std::equal(
+      std::rbegin(kArray), std::rend(kArray), span.rbegin(), span.rend()));
+  EXPECT_TRUE(std::equal(std::crbegin(kArray),
+                         std::crend(kArray),
+                         std::crbegin(span),
+                         std::crend(span)));
+}
+
+// Pigweed: These are tests for make_span, which is not included in Pigweed's
+//          implementation, since class template deduction is available.
+#if 0
+TEST(SpanTest, AsBytes) {
+  {
+    constexpr int kArray[] = {2, 3, 5, 7, 11, 13};
+    span<const uint8_t, sizeof(kArray)> bytes_span =
+        as_bytes(make_span(kArray));
+    EXPECT_EQ(reinterpret_cast<const uint8_t*>(kArray), bytes_span.data());
+    EXPECT_EQ(sizeof(kArray), bytes_span.size());
+    EXPECT_EQ(bytes_span.size(), bytes_span.size_bytes());
+  }
+
+  {
+    std::vector<int> vec = {1, 1, 2, 3, 5, 8};
+    span<int> mutable_span(vec);
+    span<const uint8_t> bytes_span = as_bytes(mutable_span);
+    EXPECT_EQ(reinterpret_cast<const uint8_t*>(vec.data()), bytes_span.data());
+    EXPECT_EQ(sizeof(int) * vec.size(), bytes_span.size());
+    EXPECT_EQ(bytes_span.size(), bytes_span.size_bytes());
+  }
+}
+
+TEST(SpanTest, AsWritableBytes) {
+  std::vector<int> vec = {1, 1, 2, 3, 5, 8};
+  span<int> mutable_span(vec);
+  span<uint8_t> writable_bytes_span = as_writable_bytes(mutable_span);
+  EXPECT_EQ(reinterpret_cast<uint8_t*>(vec.data()), writable_bytes_span.data());
+  EXPECT_EQ(sizeof(int) * vec.size(), writable_bytes_span.size());
+  EXPECT_EQ(writable_bytes_span.size(), writable_bytes_span.size_bytes());
+
+  // Set the first entry of vec to zero while writing through the span.
+  std::fill(writable_bytes_span.data(),
+            writable_bytes_span.data() + sizeof(int), 0);
+  EXPECT_EQ(0, vec[0]);
+}
+
+TEST(SpanTest, MakeSpanFromDataAndSize) {
+  int* nullint = nullptr;
+  auto empty_span = make_span(nullint, 0);
+  EXPECT_TRUE(empty_span.empty());
+  EXPECT_EQ(nullptr, empty_span.data());
+
+  std::vector<int> vector = {1, 1, 2, 3, 5, 8};
+  span<int> expected_span(vector.data(), vector.size());
+  auto made_span = make_span(vector.data(), vector.size());
+  EXPECT_EQ(expected_span.data(), made_span.data());
+  EXPECT_EQ(expected_span.size(), made_span.size());
+  static_assert(decltype(made_span)::extent == dynamic_extent, "");
+  static_assert(
+      std::is_same<decltype(expected_span), decltype(made_span)>::value,
+      "the type of made_span differs from expected_span!");
+}
+
+TEST(SpanTest, MakeSpanFromPointerPair) {
+  int* nullint = nullptr;
+  auto empty_span = make_span(nullint, nullint);
+  EXPECT_TRUE(empty_span.empty());
+  EXPECT_EQ(nullptr, empty_span.data());
+
+  std::vector<int> vector = {1, 1, 2, 3, 5, 8};
+  span<int> expected_span(vector.data(), vector.size());
+  auto made_span = make_span(vector.data(), vector.data() + vector.size());
+  EXPECT_EQ(expected_span.data(), made_span.data());
+  EXPECT_EQ(expected_span.size(), made_span.size());
+  static_assert(decltype(made_span)::extent == dynamic_extent, "");
+  static_assert(
+      std::is_same<decltype(expected_span), decltype(made_span)>::value,
+      "the type of made_span differs from expected_span!");
+}
+
+TEST(SpanTest, MakeSpanFromConstexprArray) {
+  static constexpr int kArray[] = {1, 2, 3, 4, 5};
+  constexpr span<const int, 5> expected_span(kArray);
+  constexpr auto made_span = make_span(kArray);
+  EXPECT_EQ(expected_span.data(), made_span.data());
+  EXPECT_EQ(expected_span.size(), made_span.size());
+  static_assert(decltype(made_span)::extent == 5, "");
+  static_assert(
+      std::is_same<decltype(expected_span), decltype(made_span)>::value,
+      "the type of made_span differs from expected_span!");
+}
+
+TEST(SpanTest, MakeSpanFromStdArray) {
+  const std::array<int, 5> kArray = {{1, 2, 3, 4, 5}};
+  span<const int, 5> expected_span(kArray);
+  auto made_span = make_span(kArray);
+  EXPECT_EQ(expected_span.data(), made_span.data());
+  EXPECT_EQ(expected_span.size(), made_span.size());
+  static_assert(decltype(made_span)::extent == 5, "");
+  static_assert(
+      std::is_same<decltype(expected_span), decltype(made_span)>::value,
+      "the type of made_span differs from expected_span!");
+}
+
+TEST(SpanTest, MakeSpanFromConstContainer) {
+  const std::vector<int> vector = {-1, -2, -3, -4, -5};
+  span<const int> expected_span(vector);
+  auto made_span = make_span(vector);
+  EXPECT_EQ(expected_span.data(), made_span.data());
+  EXPECT_EQ(expected_span.size(), made_span.size());
+  static_assert(decltype(made_span)::extent == dynamic_extent, "");
+  static_assert(
+      std::is_same<decltype(expected_span), decltype(made_span)>::value,
+      "the type of made_span differs from expected_span!");
+}
+
+TEST(SpanTest, MakeStaticSpanFromConstContainer) {
+  const std::vector<int> vector = {-1, -2, -3, -4, -5};
+  span<const int, 5> expected_span(vector.data(), vector.size());
+  auto made_span = make_span<5>(vector);
+  EXPECT_EQ(expected_span.data(), made_span.data());
+  EXPECT_EQ(expected_span.size(), made_span.size());
+  static_assert(decltype(made_span)::extent == 5, "");
+  static_assert(
+      std::is_same<decltype(expected_span), decltype(made_span)>::value,
+      "the type of made_span differs from expected_span!");
+}
+
+TEST(SpanTest, MakeSpanFromContainer) {
+  std::vector<int> vector = {-1, -2, -3, -4, -5};
+  span<int> expected_span(vector);
+  auto made_span = make_span(vector);
+  EXPECT_EQ(expected_span.data(), made_span.data());
+  EXPECT_EQ(expected_span.size(), made_span.size());
+  static_assert(decltype(made_span)::extent == dynamic_extent, "");
+  static_assert(
+      std::is_same<decltype(expected_span), decltype(made_span)>::value,
+      "the type of made_span differs from expected_span!");
+}
+
+TEST(SpanTest, MakeStaticSpanFromContainer) {
+  std::vector<int> vector = {-1, -2, -3, -4, -5};
+  span<int, 5> expected_span(vector.data(), vector.size());
+  auto made_span = make_span<5>(vector);
+  EXPECT_EQ(expected_span.data(), make_span<5>(vector).data());
+  EXPECT_EQ(expected_span.size(), make_span<5>(vector).size());
+  static_assert(decltype(make_span<5>(vector))::extent == 5, "");
+  static_assert(
+      std::is_same<decltype(expected_span), decltype(made_span)>::value,
+      "the type of made_span differs from expected_span!");
+}
+
+TEST(SpanTest, MakeStaticSpanFromConstexprContainer) {
+  constexpr StringPiece str = "Hello, World";
+  constexpr auto made_span = make_span<12>(str);
+  static_assert(str.data() == made_span.data(), "Error: data() does not match");
+  static_assert(str.size() == made_span.size(), "Error: size() does not match");
+  static_assert(std::is_same<decltype(str)::value_type,
+                             decltype(made_span)::value_type>::value,
+                "Error: value_type does not match");
+  static_assert(str.size() == decltype(made_span)::extent,
+                "Error: extent does not match");
+}
+
+TEST(SpanTest, MakeSpanFromRValueContainer) {
+  std::vector<int> vector = {-1, -2, -3, -4, -5};
+  span<const int> expected_span(vector);
+  // Note: While static_cast<T&&>(foo) is effectively just a fancy spelling of
+  // std::move(foo), make_span does not actually take ownership of the passed in
+  // container. Writing it this way makes it more obvious that we simply care
+  // about the right behavour when passing rvalues.
+  auto made_span = make_span(static_cast<std::vector<int>&&>(vector));
+  EXPECT_EQ(expected_span.data(), made_span.data());
+  EXPECT_EQ(expected_span.size(), made_span.size());
+  static_assert(decltype(made_span)::extent == dynamic_extent, "");
+  static_assert(
+      std::is_same<decltype(expected_span), decltype(made_span)>::value,
+      "the type of made_span differs from expected_span!");
+}
+
+TEST(SpanTest, MakeStaticSpanFromRValueContainer) {
+  std::vector<int> vector = {-1, -2, -3, -4, -5};
+  span<const int, 5> expected_span(vector.data(), vector.size());
+  // Note: While static_cast<T&&>(foo) is effectively just a fancy spelling of
+  // std::move(foo), make_span does not actually take ownership of the passed in
+  // container. Writing it this way makes it more obvious that we simply care
+  // about the right behavour when passing rvalues.
+  auto made_span = make_span<5>(static_cast<std::vector<int>&&>(vector));
+  EXPECT_EQ(expected_span.data(), made_span.data());
+  EXPECT_EQ(expected_span.size(), made_span.size());
+  static_assert(decltype(made_span)::extent == 5, "");
+  static_assert(
+      std::is_same<decltype(expected_span), decltype(made_span)>::value,
+      "the type of made_span differs from expected_span!");
+}
+
+TEST(SpanTest, MakeSpanFromDynamicSpan) {
+  static constexpr int kArray[] = {1, 2, 3, 4, 5};
+  constexpr span<const int> expected_span(kArray);
+  constexpr auto made_span = make_span(expected_span);
+  static_assert(std::is_same<decltype(expected_span)::element_type,
+                             decltype(made_span)::element_type>::value,
+                "make_span(span) should have the same element_type as span");
+
+  static_assert(expected_span.data() == made_span.data(),
+                "make_span(span) should have the same data() as span");
+
+  static_assert(expected_span.size() == made_span.size(),
+                "make_span(span) should have the same size() as span");
+
+  static_assert(decltype(made_span)::extent == decltype(expected_span)::extent,
+                "make_span(span) should have the same extent as span");
+
+  static_assert(
+      std::is_same<decltype(expected_span), decltype(made_span)>::value,
+      "the type of made_span differs from expected_span!");
+}
+
+TEST(SpanTest, MakeSpanFromStaticSpan) {
+  static constexpr int kArray[] = {1, 2, 3, 4, 5};
+  constexpr span<const int, 5> expected_span(kArray);
+  constexpr auto made_span = make_span(expected_span);
+  static_assert(std::is_same<decltype(expected_span)::element_type,
+                             decltype(made_span)::element_type>::value,
+                "make_span(span) should have the same element_type as span");
+
+  static_assert(expected_span.data() == made_span.data(),
+                "make_span(span) should have the same data() as span");
+
+  static_assert(expected_span.size() == made_span.size(),
+                "make_span(span) should have the same size() as span");
+
+  static_assert(decltype(made_span)::extent == decltype(expected_span)::extent,
+                "make_span(span) should have the same extent as span");
+
+  static_assert(
+      std::is_same<decltype(expected_span), decltype(made_span)>::value,
+      "the type of made_span differs from expected_span!");
+}
+#endif  // 0
+
+TEST(SpanTest, EnsureConstexprGoodness) {
+  static constexpr int kArray[] = {5, 4, 3, 2, 1};
+  constexpr span<const int> constexpr_span(kArray);
+  const size_t size = 2;
+
+  const size_t start = 1;
+  constexpr span<const int> subspan =
+      constexpr_span.subspan(start, start + size);
+  for (size_t i = 0; i < subspan.size(); ++i)
+    EXPECT_EQ(kArray[start + i], subspan[i]);
+
+  constexpr span<const int> firsts = constexpr_span.first(size);
+  for (size_t i = 0; i < firsts.size(); ++i)
+    EXPECT_EQ(kArray[i], firsts[i]);
+
+  constexpr span<const int> lasts = constexpr_span.last(size);
+  for (size_t i = 0; i < lasts.size(); ++i) {
+    const size_t j = (std::size(kArray) - size) + i;
+    EXPECT_EQ(kArray[j], lasts[i]);
+  }
+
+  constexpr int item = constexpr_span[size];
+  EXPECT_EQ(kArray[size], item);
+}
+
+#if 0
+
+// Pigweed: Death tests are not yet supported.
+TEST(SpanTest, OutOfBoundsDeath) {
+  constexpr span<int, 0> kEmptySpan;
+  ASSERT_DEATH_IF_SUPPORTED(kEmptySpan[0], "");
+  ASSERT_DEATH_IF_SUPPORTED(kEmptySpan.first(1), "");
+  ASSERT_DEATH_IF_SUPPORTED(kEmptySpan.last(1), "");
+  ASSERT_DEATH_IF_SUPPORTED(kEmptySpan.subspan(1), "");
+
+  constexpr span<int> kEmptyDynamicSpan;
+  ASSERT_DEATH_IF_SUPPORTED(kEmptyDynamicSpan[0], "");
+  ASSERT_DEATH_IF_SUPPORTED(kEmptyDynamicSpan.front(), "");
+  ASSERT_DEATH_IF_SUPPORTED(kEmptyDynamicSpan.first(1), "");
+  ASSERT_DEATH_IF_SUPPORTED(kEmptyDynamicSpan.last(1), "");
+  ASSERT_DEATH_IF_SUPPORTED(kEmptyDynamicSpan.back(), "");
+  ASSERT_DEATH_IF_SUPPORTED(kEmptyDynamicSpan.subspan(1), "");
+
+  static constexpr int kArray[] = {0, 1, 2};
+  constexpr span<const int> kNonEmptyDynamicSpan(kArray);
+  EXPECT_EQ(3U, kNonEmptyDynamicSpan.size());
+  ASSERT_DEATH_IF_SUPPORTED(kNonEmptyDynamicSpan[4], "");
+  ASSERT_DEATH_IF_SUPPORTED(kNonEmptyDynamicSpan.subspan(10), "");
+  ASSERT_DEATH_IF_SUPPORTED(kNonEmptyDynamicSpan.subspan(1, 7), "");
+}
+
+// Pigweed: These tests use CheckedContiguousConstIterator, which isn't used in
+//          Pigweed's version.
+TEST(SpanTest, IteratorIsRangeMoveSafe) {
+  static constexpr int kArray[] = {1, 6, 1, 8, 0};
+  const size_t kNumElements = 5;
+  constexpr span<const int> span(kArray);
+
+  static constexpr int kOverlappingStartIndexes[] = {-4, 0, 3, 4};
+  static constexpr int kNonOverlappingStartIndexes[] = {-7, -5, 5, 7};
+
+  // Overlapping ranges.
+  for (const int dest_start_index : kOverlappingStartIndexes) {
+    EXPECT_FALSE(CheckedContiguousIterator<const int>::IsRangeMoveSafe(
+        span.begin(), span.end(),
+        CheckedContiguousIterator<const int>(
+            span.data() + dest_start_index,
+            span.data() + dest_start_index + kNumElements)));
+    EXPECT_FALSE(CheckedContiguousConstIterator<const int>::IsRangeMoveSafe(
+        std::cbegin(span), std::cend(span),
+        CheckedContiguousConstIterator<const int>(
+            span.data() + dest_start_index,
+            span.data() + dest_start_index + kNumElements)));
+  }
+
+  // Non-overlapping ranges.
+  for (const int dest_start_index : kNonOverlappingStartIndexes) {
+    EXPECT_TRUE(CheckedContiguousIterator<const int>::IsRangeMoveSafe(
+        span.begin(), span.end(),
+        CheckedContiguousIterator<const int>(
+            span.data() + dest_start_index,
+            span.data() + dest_start_index + kNumElements)));
+    EXPECT_TRUE(CheckedContiguousConstIterator<const int>::IsRangeMoveSafe(
+        std::cbegin(span), std::cend(span),
+        CheckedContiguousConstIterator<const int>(
+            span.data() + dest_start_index,
+            span.data() + dest_start_index + kNumElements)));
+  }
+
+  // IsRangeMoveSafe is true if the length to be moved is 0.
+  EXPECT_TRUE(CheckedContiguousIterator<const int>::IsRangeMoveSafe(
+      span.begin(), span.begin(),
+      CheckedContiguousIterator<const int>(span.data(), span.data())));
+  EXPECT_TRUE(CheckedContiguousConstIterator<const int>::IsRangeMoveSafe(
+      std::cbegin(span), std::cbegin(span),
+      CheckedContiguousConstIterator<const int>(span.data(), span.data())));
+
+  // IsRangeMoveSafe is false if end < begin.
+  EXPECT_FALSE(CheckedContiguousIterator<const int>::IsRangeMoveSafe(
+      span.end(), span.begin(),
+      CheckedContiguousIterator<const int>(span.data(), span.data())));
+  EXPECT_FALSE(CheckedContiguousConstIterator<const int>::IsRangeMoveSafe(
+      std::cend(span), std::cbegin(span),
+      CheckedContiguousConstIterator<const int>(span.data(), span.data())));
+}
+
+// Pigweed: gMock matchers are not yet supported.
+TEST(SpanTest, Sort) {
+  int array[] = {5, 4, 3, 2, 1};
+
+  span<int> dynamic_span = array;
+  std::sort(dynamic_span.begin(), dynamic_span.end());
+  EXPECT_THAT(array, ElementsAre(1, 2, 3, 4, 5));
+  std::sort(dynamic_span.rbegin(), dynamic_span.rend());
+  EXPECT_THAT(array, ElementsAre(5, 4, 3, 2, 1));
+
+  span<int, 5> static_span = array;
+  std::sort(static_span.rbegin(), static_span.rend(), std::greater<>());
+  EXPECT_THAT(array, ElementsAre(1, 2, 3, 4, 5));
+  std::sort(static_span.begin(), static_span.end(), std::greater<>());
+  EXPECT_THAT(array, ElementsAre(5, 4, 3, 2, 1));
+}
+#endif  // 0
+
+TEST(SpanTest, SpanExtentConversions) {
+  // Statically checks that various conversions between spans of dynamic and
+  // static extent are possible or not.
+  static_assert(
+      !std::is_constructible<span<int, 0>, span<int>>::value,
+      "Error: static span should not be constructible from dynamic span");
+
+  static_assert(!std::is_constructible<span<int, 2>, span<int, 1>>::value,
+                "Error: static span should not be constructible from static "
+                "span with different extent");
+
+  static_assert(std::is_convertible<span<int, 0>, span<int>>::value,
+                "Error: static span should be convertible to dynamic span");
+
+  static_assert(std::is_convertible<span<int>, span<int>>::value,
+                "Error: dynamic span should be convertible to dynamic span");
+
+  static_assert(std::is_convertible<span<int, 2>, span<int, 2>>::value,
+                "Error: static span should be convertible to static span");
+}
+
+TEST(SpanTest, IteratorConversions) {
+  static_assert(std::is_convertible<span<int>::iterator,
+                                    span<const int>::iterator>::value,
+                "Error: iterator should be convertible to const iterator");
+
+  static_assert(!std::is_convertible<span<const int>::iterator,
+                                     span<int>::iterator>::value,
+                "Error: const iterator should not be convertible to iterator");
+}
+
+}  // namespace pw
diff --git a/pw_span/span_test.cc b/pw_span/span_test.cc
index 37d5ee4..e41a006 100644
--- a/pw_span/span_test.cc
+++ b/pw_span/span_test.cc
@@ -25,6 +25,7 @@
 #include <algorithm>
 #include <cstdint>
 #include <memory>
+#include <span>
 #include <string>
 #include <type_traits>
 #include <vector>
@@ -38,7 +39,7 @@
 using ::testing::Pointwise;
 #endif  // 0
 
-namespace pw {
+namespace std {
 
 namespace {
 
@@ -58,6 +59,59 @@
 
 }  // namespace
 
+// TODO(hepler): Remove these tests after eliminating pw::span.
+TEST(StdSpanCompatibility, ConstructFromPwSpanToStdSpan) {
+  char array[] = {'a', 'b', 'c', 'd', '\0'};
+
+  ::pw::span pw_span(array);
+  std::span std_span(pw_span);
+
+  std_span[0] = '!';
+  EXPECT_STREQ(std_span.data(), "!bcd");
+
+  EXPECT_EQ(pw_span.data(), std_span.data());
+  EXPECT_EQ(pw_span.size(), std_span.size());
+}
+
+TEST(StdSpanCompatibility, ConstructFromStdSpanToPwSpan) {
+  char array[] = {'a', 'b', 'c', 'd', '\0'};
+
+  std::span std_span(array);
+  ::pw::span pw_span(std_span);
+
+  pw_span[0] = '!';
+  EXPECT_STREQ(pw_span.data(), "!bcd");
+
+  EXPECT_EQ(pw_span.data(), std_span.data());
+  EXPECT_EQ(pw_span.size(), std_span.size());
+}
+
+TEST(StdSpanCompatibility, AssignFromPwSpanToStdSpan) {
+  char array[] = {'a', 'b', 'c', 'd', '\0'};
+
+  auto pw_span = ::pw::span(array);
+  std::span std_span = pw_span;
+
+  std_span[0] = '!';
+  EXPECT_STREQ(std_span.data(), "!bcd");
+
+  EXPECT_EQ(pw_span.data(), std_span.data());
+  EXPECT_EQ(pw_span.size(), std_span.size());
+}
+
+TEST(StdSpanCompatibility, AssignFromStdSpanToPwSpan) {
+  char array[] = {'a', 'b', 'c', 'd', '\0'};
+
+  auto std_span = std::span(array);
+  ::pw::span pw_span = std_span;
+
+  pw_span[0] = '!';
+  EXPECT_STREQ(pw_span.data(), "!bcd");
+
+  EXPECT_EQ(pw_span.data(), std_span.data());
+  EXPECT_EQ(pw_span.size(), std_span.size());
+}
+
 TEST(SpanTest, DeductionGuides_MutableArray) {
   char array[] = {'a', 'b', 'c', 'd', '\0'};
 
@@ -1629,4 +1683,4 @@
                 "Error: const iterator should not be convertible to iterator");
 }
 
-}  // namespace pw
+}  // namespace std