diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..ff18a80
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,6 @@
+---
+BasedOnStyle: Google
+---
+Language: Cpp
+DerivePointerAlignment: false
+PointerAlignment: Left
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..94ee531
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,30 @@
+# Copyright 2019 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.
+cmake_minimum_required(VERSION 3.13)
+
+enable_testing()
+find_package(GTest MODULE REQUIRED)
+
+# Include directories accessible from here.
+include_directories(.)
+
+# Require C++17 with no extensions.
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+
+# Add the test to the std::expected implementation.
+add_executable(expected_test netlib/expected_test.cc)
+target_link_libraries(expected_test PRIVATE GTest::GTest GTest::Main)
+add_test(expected_test expected_test)
diff --git a/netlib/README.md b/netlib/README.md
new file mode 100644
index 0000000..46f9243
--- /dev/null
+++ b/netlib/README.md
@@ -0,0 +1,29 @@
+# netlib Directory
+
+This is the main source directory for the project. The intent is to keep this
+directory flat with subdirectories for logical groupings. This means all the
+headers, implementation, and test code should be co-hosted in this directory.
+
+## Structure
+
+All implementation files must end with the `.cc` filename extension, and all
+headers must end in `.h`. If we have a file named `connection.cc` the header
+must be `connection.h` and the test(s) should be in `connection_test.cc`.
+
+We shall control the installed headers through our CMake configuration
+instead of assuming that all headers are publicly accessible. When including
+files, we should always include headers in the netlib repository by relative
+inclusion with the `netlib/` directory (based off the root of the
+repository). As an example:
+
+```c++
+// In connection.cc and connection_test.cc.
+#include "netlib/connection.h"
+```
+
+## Subdirectories
+
+We can introduce subdirectories for logical grouping, each one following the
+same structure rules as described here. For instance, if we have a
+subdirectory of encoding/decoding, we can introduce a `coding/` subdirectory
+with all the encoders and decoders implemented.
\ No newline at end of file
diff --git a/netlib/expected.h b/netlib/expected.h
new file mode 100644
index 0000000..514b3f3
--- /dev/null
+++ b/netlib/expected.h
@@ -0,0 +1,474 @@
+// Copyright 2019 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.
+#ifndef CPP_NETLIB_EXPECTED_H_
+#define CPP_NETLIB_EXPECTED_H_
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+
+namespace cppnetlib {
+
+/// This is a minimal implementation of the proposed P0323R3
+/// std::unexpected<...> API.
+template <class E>
+// requires EqualityComparable<E> && (CopyConstructible<E> ||
+// MoveConstructible<E>)
+class unexpected {
+ public:
+  static_assert(!std::is_same_v<E, void>, "unexpected<void> is not supported.");
+
+  unexpected() = delete;
+  constexpr explicit unexpected(const E& e) : value_(e) {}
+  constexpr explicit unexpected(E&& e) : value_(std::move(e)) {}
+  constexpr const E& value() const& { return value_; }
+  constexpr E& value() & { return value_; }
+  constexpr E&& value() && { return std::move(value_); }
+  constexpr const E&& value() const&& { return std::move(value_); }
+
+  // This is a deviation from the proposal which suggests that these functions
+  // are namespace-level functions, instead of ADL-only found comparison
+  // operators (defined friend free functions).
+  template <class F>
+  friend constexpr bool operator==(const unexpected<F>& lhs,
+                                   const unexpected<F>& rhs) {
+    return lhs.value_ == rhs.value_;
+  }
+
+  template <class F>
+  friend constexpr bool operator!=(const unexpected<F>& lhs,
+                                   const unexpected<F>& rhs) {
+    return lhs.value_ == rhs.value_;
+  }
+
+ private:
+  E value_;
+};
+
+struct unexpect_t {
+  unexpect_t() = default;
+};
+inline constexpr unexpect_t unexpect{};
+
+template <class E>
+class bad_expected_access;
+
+template <>
+class bad_expected_access<void> {
+ public:
+  virtual const char* what() const noexcept {
+    return "cppnetlib::bad_expected_access";
+  }
+  virtual ~bad_expected_access() {}
+};
+
+template <class E>
+class bad_expected_access : public bad_expected_access<void> {
+ public:
+  explicit bad_expected_access(E e) : val_(e) {}
+  const char* what() const noexcept override {
+    return "cppnetlib::bad_expected_access<E>";
+  }
+  const E& error() const&;
+  E& error() &;
+  E&& error() &&;
+
+ private:
+  E val_;
+};
+
+/// This is a minimal implementation of the proposed P0323R3
+/// std::expected<...> API.
+// TODO: Implement a specilisation of expected<void, E>.
+// TODO: Implement more member functions as needed.
+template <class T, class E>
+class [[nodiscard]] expected {
+ public:
+  using value_type = T;
+  using error_type = E;
+  using unexpected_type = unexpected<E>;
+
+  template <class U>
+  struct rebind {
+    using type = expected<U, error_type>;
+  };
+
+  constexpr expected() : has_value_(false) {
+    new (&union_storage_) T();
+    has_value_ = true;
+  }
+  constexpr expected(const expected& other)
+      : union_storage_(other.union_storage_), has_value_(other.has_value_) {}
+
+  constexpr expected(expected && other,
+                     std::enable_if_t < std::is_move_constructible_v<T> &&
+                         std::is_move_constructible_v<E>> * =
+                         0) noexcept(std::is_nothrow_move_constructible_v<T> &&
+                                     std::is_nothrow_move_constructible_v<E>)
+      : has_value_(other.has_value_) {
+    if (other.has_value_)
+      new (union_storage_)
+          T(std::move(*reinterpret_cast<T*>(other.union_storage_)));
+    else
+      new (union_storage_)
+          unexpected<E>(std::move(*reinterpret_cast<E*>(other.union_storage_)));
+  }
+
+ private:
+  template <class U, class G>
+  using constructor_helper_t =
+      std::enable_if_t<std::is_constructible_v<T, const U&> and
+                       std::is_constructible_v<E, const G&> and
+                       !std::is_constructible_v<T, expected<U, G>&> and
+                       !std::is_constructible_v<T, expected<U, G>&&> and
+                       !std::is_constructible_v<T, const expected<U, G>&> and
+                       !std::is_constructible_v<T, const expected<U, G>&&> and
+                       !std::is_convertible_v<expected<U, G>&, T> and
+                       !std::is_convertible_v<expected<U, G>&&, T> and
+                       !std::is_convertible_v<const expected<U, G>&, T> and
+                       !std::is_convertible_v<const expected<U, G>&&, T>>;
+
+ public:
+  // TODO: c++20 has support for conditional explicit, use that instead of the
+  // duplication.
+  template <class U, class G,
+            std::enable_if_t<!(std::is_convertible_v<const U&, T> and
+                               std::is_convertible_v<const G&, E>),
+                             bool> = false>
+  explicit constexpr expected(const expected<U, G>& other,
+                              constructor_helper_t<U, G>* = 0)
+      : has_value_(other.has_value_) {
+    if (other.has_value_)
+      new (&union_storage_) T(*other);
+    else
+      new (&union_storage_) unexpected<E>(other.error());
+  }
+
+  template <class U, class G,
+            std::enable_if_t<(std::is_convertible_v<const U&, T> and
+                              std::is_convertible_v<const G&, E>),
+                             bool> = false>
+  constexpr expected(const expected<U, G>& other,
+                     constructor_helper_t<U, G>* = 0)
+      : has_value_(other.has_value_) {
+    if (other.has_value_)
+      new (&union_storage_) T(*other);
+    else
+      new (&union_storage_) unexpected<E>(other.error());
+  }
+
+  template <class U, class G,
+            std::enable_if_t<!(std::is_convertible_v<const U&, T> and
+                               std::is_convertible_v<const G&, E>),
+                             bool> = false>
+  explicit constexpr expected(const expected<U, G>&& other,
+                              constructor_helper_t<U, G>* = 0)
+      : has_value_(other.has_value_) {
+    if (other.has_value_)
+      new (&union_storage_) T(std::move(*other));
+    else
+      new (&union_storage_) unexpected<E>(std::move(unexpected(other.error())));
+  }
+
+  template <class U = T,
+            std::enable_if_t<!std::is_convertible_v<U&&, T>, bool> = false>
+  explicit constexpr expected(
+      U && value,
+      std::enable_if_t<std::is_constructible_v<T, U&&> and
+                       !std::is_same_v<std::decay_t<U>, std::in_place_t> and
+                       !std::is_same_v<expected<T, E>, std::decay_t<U>> and
+                       !std::is_same_v<unexpected<E>, std::decay_t<U>>>* = 0)
+      : has_value_(true) {
+    new (&union_storage_) U(std::forward<U>(std::move(value)));
+  }
+
+  template <class U = T,
+            std::enable_if_t<std::is_convertible_v<U&&, T>, bool> = false>
+  constexpr expected(
+      U && value,
+      std::enable_if_t<std::is_constructible_v<T, U&&> and
+                       !std::is_same_v<std::decay_t<U>, std::in_place_t> and
+                       !std::is_same_v<expected<T, E>, std::decay_t<U>> and
+                       !std::is_same_v<unexpected<E>, std::decay_t<U>>>* = 0)
+      : has_value_(true) {
+    new (&union_storage_) U(std::forward<U>(value));
+  }
+
+  template <class G = E,
+            std::enable_if_t<!std::is_convertible_v<const G&, E>, bool> = false>
+  explicit constexpr expected(unexpected<G> const& e) : has_value_(false) {
+    new (&union_storage_) unexpected<E>(e);
+  }
+
+  template <class G = E,
+            std::enable_if_t<std::is_convertible_v<const G&, E>, bool> = false>
+  constexpr expected(unexpected<G> const& e) : has_value_(false) {
+    new (&union_storage_) unexpected<E>(e);
+  }
+
+  template <class G = E,
+            std::enable_if_t<!std::is_convertible_v<G&&, E>, bool> = false>
+  explicit constexpr expected(unexpected<G> && e) noexcept(
+      std::is_nothrow_move_constructible_v<E, G&&>)
+      : has_value_(false) {
+    new (&union_storage_) unexpected<E>(std::move(e.value()));
+  }
+
+  template <class G = E,
+            std::enable_if_t<std::is_convertible_v<G&&, E>, bool> = false>
+  constexpr expected(unexpected<G> &&
+                     e) noexcept(std::is_nothrow_constructible_v<E, G&&>)
+      : has_value_(false) {
+    new (&union_storage_) unexpected<E>(std::move(e.value()));
+  }
+
+  // Destructor.
+  ~expected() {
+    if constexpr (!std::is_trivially_destructible_v<T>) {
+      if (has_value_)
+        reinterpret_cast<T*>(&union_storage_)->~T();
+      else
+        reinterpret_cast<unexpected_type*>(&union_storage_)->~unexpected_type();
+    }
+  }
+
+  // Assignment.
+  expected& operator=(const expected& other) {
+    if (has_value_ and other.has_value_) {
+      **this = *other;
+      return *this;
+    }
+
+    if (!has_value_ and !other.has_value_) {
+      (*reinterpret_cast<unexpected_type*>(&union_storage_)) =
+          unexpected(other.error());
+      return *this;
+    }
+
+    if (has_value_ and !other.has_value_) {
+      reinterpret_cast<T*>(&union_storage_)->~T();
+      new (&union_storage_) unexpected_type(unexpected(other.error()));
+      has_value_ = false;
+      return *this;
+    }
+
+    assert(!has_value_ and other.has_value_);
+    if constexpr (std::is_nothrow_copy_constructible_v<T>) {
+      reinterpret_cast<unexpected_type*>(&union_storage_)->~unexpected_type();
+      new (&union_storage_) T(other.value());
+      has_value_ = true;
+    } else if constexpr (std::is_nothrow_move_constructible_v<T>) {
+      T tmp = *other;
+      reinterpret_cast<unexpected_type*>(&union_storage_)->~unexpected_type();
+      new (&union_storage_) T(tmp);
+      has_value_ = true;
+    } else if constexpr (std::is_nothrow_move_constructible_v<E>) {
+      unexpected_type tmp = unexpected(std::move(error()));
+      reinterpret_cast<unexpected_type*>(&union_storage_)->~unexpected_type();
+      try {
+        new (&union_storage_) T(*other);
+        has_value_ = true;
+      } catch (...) {
+        new (&union_storage_) unexpected_type(std::move(tmp));
+        throw;
+      }
+    }
+
+    return *this;
+  }
+
+  expected& operator=(expected&& other) noexcept(
+      std::is_nothrow_move_assignable_v<T> and
+      std::is_nothrow_move_constructible_v<T>) {
+    if (has_value_ and other.has_value_) {
+      **this = std::move(*other);
+      return *this;
+    }
+
+    if (!has_value_ and !other.has_value_) {
+      (*reinterpret_cast<unexpected_type*>(&union_storage_)) =
+          unexpected(std::move(other.error()));
+      return *this;
+    }
+
+    if (has_value_ and !other.has_value_) {
+      reinterpret_cast<T*>(&union_storage_)->~T();
+      new (&union_storage_) unexpected_type(
+          std::move(std::forward<expected<T, E>>(other).error()));
+      has_value_ = false;
+      return *this;
+    }
+
+    assert(!has_value_ and other.has_value_);
+    if constexpr (std::is_nothrow_move_constructible_v<T>) {
+      reinterpret_cast<T*>(&union_storage_)->~T();
+      new (&union_storage_) T(*std::move(other));
+      has_value_ = true;
+    } else if constexpr (std::is_nothrow_move_constructible_v<E>()) {
+      unexpected_type tmp = unexpected(std::move(error()));
+      reinterpret_cast<unexpected_type*>(&union_storage_)->~unexpected_type();
+      try {
+        new (&union_storage_) T(*std::move(other));
+        has_value_ = true;
+      } catch (...) {
+        new (&union_storage_) unexpected_type(std::move(tmp));
+        throw;
+      }
+    }
+
+    return *this;
+  }
+
+  template <std::enable_if_t<std::is_nothrow_copy_constructible_v<E> and
+                                 std::is_assignable_v<E&, E>,
+                             bool> = false>
+  expected& operator=(const unexpected<E>& e) noexcept(
+      std::is_nothrow_copy_assignable_v<unexpected_type> and
+      std::is_nothrow_copy_constructible_v<unexpected_type>) {
+    if (!has_value_) {
+      (*reinterpret_cast<unexpected_type*>(&union_storage_)) = e;
+      return *this;
+    }
+
+    reinterpret_cast<T*>(&union_storage_)->~T();
+    new (&union_storage_)
+        unexpected_type(unexpected(std::forward<unexpected_type>(e)));
+    has_value_ = false;
+    return *this;
+  }
+
+  template <std::enable_if_t<std::is_nothrow_move_constructible_v<E> and
+                                 std::is_nothrow_move_assignable_v<E>,
+                             bool> = false>
+  expected& operator=(unexpected<E>&& e) noexcept(
+      std::is_nothrow_move_assignable_v<unexpected_type>) {
+    if (!has_value_) {
+      (*reinterpret_cast<unexpected_type*>(&union_storage_)) =
+          unexpected(std::move(std::forward<unexpected<E>>(e)));
+      return *this;
+    }
+
+    reinterpret_cast<T*>(&union_storage_)->~T();
+    new (&union_storage_)
+        unexpected_type(unexpected(std::forward<unexpected_type>(e)));
+    has_value_ = false;
+    return *this;
+  }
+
+  template <
+      class U,
+      std::enable_if_t<
+          !std::is_same_v<expected<T, E>, std::decay_t<U>> and
+              !std::conjunction_v<std::is_scalar<T>,
+                                  std::is_same<T, std::decay_t<U>>> and
+              std::is_constructible_v<T, U> and std::is_assignable_v<T&, U> and
+              std::is_nothrow_move_constructible_v<E>,
+          bool> = false>
+  expected& operator=(U&& value) {
+    if (has_value_) {
+      this->value() = std::forward<U>(value);
+      return *this;
+    }
+
+    if constexpr (std::is_nothrow_constructible_v<T, U&&>) {
+      reinterpret_cast<unexpected_type*>(&union_storage_)->~unexpected_type();
+      new (&union_storage_) T(std::forward<U>(value));
+      has_value_ = true;
+    } else if constexpr (std::is_nothrow_constructible_v<E, U&&>) {
+      unexpected_type tmp(std::move(error()));
+      reinterpret_cast<unexpected_type*>(&union_storage_)->~unexpected_type();
+      try {
+        new (&union_storage_) T(std::forward<U>(value));
+        has_value_ = true;
+      } catch (...) {
+        new (&union_storage_) unexpected_type(std::move(tmp));
+        throw;
+      }
+    } 
+    return *this;
+  }
+
+  // Observer functions.
+  constexpr const T* operator->() const {
+    if (!has_value_) throw bad_expected_access<E>(error());
+    return reinterpret_cast<const T*>(&union_storage_);
+  }
+
+  constexpr T* operator->() {
+    if (!has_value_) throw bad_expected_access<E>(error());
+    return reinterpret_cast<T*>(&union_storage_);
+  }
+
+  constexpr const T& operator*() const& {
+    if (!has_value_) throw bad_expected_access<E>(error());
+    return *reinterpret_cast<const T*>(&union_storage_);
+  }
+
+  constexpr T& operator*()& {
+    if (!has_value_) throw bad_expected_access<E>(error());
+    return *reinterpret_cast<T*>(&union_storage_);
+  }
+
+  constexpr const T&& operator*() const&& {
+    if (!has_value_) throw bad_expected_access<E>(error());
+    return std::move(*reinterpret_cast<const T*>(&union_storage_));
+  }
+
+  constexpr T&& operator*()&& {
+    if (!has_value_) throw bad_expected_access<E>(error());
+    return std::move(*reinterpret_cast<T*>(&union_storage_));
+  }
+
+  constexpr explicit operator bool() const noexcept { return has_value_; }
+  constexpr bool has_value() const noexcept { return has_value_; }
+
+  constexpr const T& value() const& { return **this; }
+  constexpr T& value()& { return **this; }
+  constexpr const T&& value() const&& { return std::move(**this); }
+  constexpr T&& value()&& { return std::move(**this); }
+
+  constexpr const E& error() const& {
+    assert(!has_value_ &&
+           "expected<T, E> must not have a value when taking an error!");
+    return reinterpret_cast<const unexpected<E>*>(&union_storage_)->value();
+  }
+
+  constexpr E& error()& {
+    assert(!has_value_ &&
+           "expected<T, E> must not have a value when taking an error!");
+    return reinterpret_cast<unexpected<E>*>(&union_storage_)->value();
+  }
+
+  constexpr const E&& error() const&& {
+    assert(!has_value_ &&
+           "expected<T, E> must not have a value when taking an error!");
+    return std::move(*reinterpret_cast<const unexpected<E>*>(&union_storage_))
+        ->value();
+  }
+
+  constexpr E&& error()&& {
+    assert(!has_value_ &&
+           "expected<T, E> must not have a value when taking an error!");
+    return std::move(*reinterpret_cast<unexpected<E>*>(&union_storage_))
+        .value();
+  };
+
+ private:
+  std::aligned_union_t<8, value_type, unexpected_type> union_storage_;
+  bool has_value_;
+};
+
+}  // namespace cppnetlib
+
+#endif  // CPP_NETLIB_EXPECTED_H_
diff --git a/netlib/expected_test.cc b/netlib/expected_test.cc
new file mode 100644
index 0000000..8e0f14e
--- /dev/null
+++ b/netlib/expected_test.cc
@@ -0,0 +1,102 @@
+// Copyright 2019 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 "netlib/expected.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace cppnetlib {
+namespace {
+
+using ::testing::Eq;
+
+using error_code = int;
+
+enum errors : error_code { undefined };
+
+expected<bool, error_code> f(bool b) {
+  if (b) return true;
+  return unexpected(errors::undefined);
+}
+
+// For testing support for larger types.
+struct test_data {
+  int64_t first;
+  int64_t second;
+};
+
+expected<test_data, error_code> g(bool b, int64_t first, int64_t second) {
+  if (b) return unexpected{errors::undefined};
+  return test_data{first, second};
+}
+
+TEST(ExpectedTest, Construction) { expected<bool, error_code> e; }
+
+TEST(ExpectedTest, Unexpected) {
+  auto e1 = f(true);
+  ASSERT_TRUE(e1);
+
+  auto e2 = f(false);
+  ASSERT_FALSE(e2);
+  ASSERT_THROW(*e2, bad_expected_access<error_code>);
+
+  auto e3 = g(true, 1, 2);
+  ASSERT_FALSE(e3);
+  EXPECT_THAT(e3.error(), Eq(errors::undefined));
+  ASSERT_THROW(*e3, bad_expected_access<error_code>);
+
+  e3 = g(false, 2, 3);
+  ASSERT_TRUE(e3);
+  ASSERT_THAT(e3->first, Eq(2));
+  ASSERT_THAT(e3->second, Eq(3));
+}
+
+TEST(ExpectedTest, AssignmentSimple) {
+  expected<int, error_code> e;
+  ASSERT_NO_THROW(e = 1);
+  EXPECT_THAT(e.value(), Eq(1));
+  ASSERT_NO_THROW(e = {});
+  EXPECT_THAT(e.value(), Eq(int{}));
+  ASSERT_NO_THROW(e = unexpected{errors::undefined});
+  ASSERT_THROW(*e, bad_expected_access<error_code>);
+  EXPECT_THAT(e.error(), Eq(errors::undefined));
+}
+
+struct throwing_copy_exception : public std::exception {
+  const char* what() const noexcept override {
+    return "throwing copy exception";
+  }
+};
+
+struct throwing_copy {
+  throwing_copy() = default;
+  throwing_copy(const throwing_copy& e) { throw throwing_copy_exception(); }
+  throwing_copy& operator=(const throwing_copy&) {
+    throw throwing_copy_exception();
+  }
+  throwing_copy(throwing_copy&&) = default;
+  throwing_copy& operator=(throwing_copy&&) = default;
+  ~throwing_copy() = default;
+};
+
+TEST(ExpectedTest, AssignmentThrowingCopy) {
+  expected<throwing_copy, error_code> instance;
+  ASSERT_NO_THROW(instance = throwing_copy{});
+  throwing_copy tmp;
+  ASSERT_NO_THROW(instance = std::move(tmp));
+  ASSERT_THROW(instance = tmp, throwing_copy_exception);
+  ASSERT_THROW(*instance = tmp, throwing_copy_exception);
+}
+
+}  // namespace
+}  // namespace cppnetlib