Squashed 'third_party/autocxx/' content from commit 629e8fa53

git-subtree-dir: third_party/autocxx
git-subtree-split: 629e8fa531a633164c0b52e2a3cab536d4cd0849
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
Change-Id: I62a03b0049f49adf029e0204639cdb5468dde1a1
diff --git a/examples/chromium-fake-render-frame-host/Cargo.toml b/examples/chromium-fake-render-frame-host/Cargo.toml
new file mode 100644
index 0000000..a961708
--- /dev/null
+++ b/examples/chromium-fake-render-frame-host/Cargo.toml
@@ -0,0 +1,21 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+[package]
+name = "autocxx-chromium-fake-render-frame-host-example"
+version = "0.1.0"
+authors = ["Adrian Taylor <adetaylor@chromium.org>"]
+edition = "2021"
+
+[dependencies]
+cxx = "1.0.54"
+autocxx = { path = "../..", version="0.22.0" }
+
+[build-dependencies]
+autocxx-build = { path = "../../gen/build", version="0.22.0" }
+miette = { version="4.3", features = [ "fancy" ] }
diff --git a/examples/chromium-fake-render-frame-host/build.rs b/examples/chromium-fake-render-frame-host/build.rs
new file mode 100644
index 0000000..b533af4
--- /dev/null
+++ b/examples/chromium-fake-render-frame-host/build.rs
@@ -0,0 +1,20 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() -> miette::Result<()> {
+    let path = std::path::PathBuf::from("src");
+    let mut b = autocxx_build::Builder::new("src/main.rs", &[&path]).build()?;
+    b.flag_if_supported("-std=c++17")       // clang
+        .flag_if_supported("/std:c++17")    // msvc
+        .file("src/fake-chromium-src.cc")
+        .compile("autocxx-fake-render-frame-host-example");
+    println!("cargo:rerun-if-changed=src/main.rs");
+    println!("cargo:rerun-if-changed=src/fake-chromium-src.cc");
+    println!("cargo:rerun-if-changed=src/fake-chromium-header.h");
+    Ok(())
+}
diff --git a/examples/chromium-fake-render-frame-host/src/fake-chromium-header.h b/examples/chromium-fake-render-frame-host/src/fake-chromium-header.h
new file mode 100644
index 0000000..8f1c532
--- /dev/null
+++ b/examples/chromium-fake-render-frame-host/src/fake-chromium-header.h
@@ -0,0 +1,78 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#pragma once
+#include <memory>
+#include <string>
+#include <vector>
+
+// This is supposed to be a _fairly_ faithful representation of a few
+// Chromium codebase APIs. Just enough that we can start to experiment
+// with ownership patterns.
+
+namespace content {
+
+class RenderFrameHost {
+public:
+  static RenderFrameHost *FromId(int process_id, int frame_id);
+  virtual int GetRoutingID() = 0;
+
+  /// Returns the assigned name of the frame, the name of the iframe tag
+  /// declaring it. For example, <iframe name="framename">[...]</iframe>. It is
+  /// quite possible for a frame to have no name, in which case GetFrameName
+  /// will return an empty string.
+  virtual std::string GetFrameName() = 0;
+  virtual ~RenderFrameHost() {}
+};
+
+class CreateParams {
+public:
+  CreateParams(const std::string &);
+  std::string main_frame_name_;
+};
+
+class WebContentsObserver;
+
+class WebContents {
+public:
+  static std::unique_ptr<WebContents> Create(const CreateParams &params);
+
+  static WebContents *FromFrameTreeNodeId(int frame_tree_node_id);
+
+  // TODO - should not be in WebContents, just WebContentsImpl
+  virtual void AddObserver(WebContentsObserver *) {}
+  virtual void RemoveObserver(WebContentsObserver *) {}
+
+  virtual ~WebContents(){};
+
+  virtual const std::string &GetTitle() = 0;
+};
+
+class WebContentsObserver {
+public:
+  virtual void RenderFrameCreated(RenderFrameHost *) {}
+  virtual void RenderFrameDeleted(RenderFrameHost *) {}
+  virtual ~WebContentsObserver() {}
+};
+
+class WebContentsImpl : public WebContents {
+public:
+  void AddObserver(WebContentsObserver *);
+  void RemoveObserver(WebContentsObserver *);
+  const std::string &GetTitle();
+  WebContentsImpl(const CreateParams &);
+  void DeleteRFH();
+
+private:
+  std::string title_;
+  std::vector<WebContentsObserver *> observers_;
+  std::vector<std::unique_ptr<RenderFrameHost>> rfhs_;
+};
+} // namespace content
+
+void SimulateRendererShutdown(int frame_id);
\ No newline at end of file
diff --git a/examples/chromium-fake-render-frame-host/src/fake-chromium-src.cc b/examples/chromium-fake-render-frame-host/src/fake-chromium-src.cc
new file mode 100644
index 0000000..2f9a9d4
--- /dev/null
+++ b/examples/chromium-fake-render-frame-host/src/fake-chromium-src.cc
@@ -0,0 +1,81 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#include "fake-chromium-header.h"
+#include <map>
+#include <algorithm>
+
+using namespace content;
+
+// This is all appalling. None of this is real Chromium code.
+// It's just designed to be the bare minimum required
+// to knock together a quick Rust-side demo. In some future realities, all
+// this is replaced with real Chromium code.
+
+int latest_rfh_id = 0;
+std::map<int, RenderFrameHost *> render_frame_hosts;
+WebContentsImpl *the_only_web_contents; // for this daft demo
+
+CreateParams::CreateParams(const std::string &main_frame_name)
+    : main_frame_name_(main_frame_name) {}
+
+RenderFrameHost *RenderFrameHost::FromId(int, int frame_id) {
+  return render_frame_hosts.at(frame_id);
+}
+
+class RenderFrameHostImpl : public RenderFrameHost {
+public:
+  RenderFrameHostImpl(const std::string name, int routing_id)
+      : routing_id_(routing_id), name_(name) {}
+  virtual int GetRoutingID() { return routing_id_; }
+  virtual std::string GetFrameName() { return name_; }
+
+private:
+  int routing_id_;
+  std::string name_;
+};
+
+std::unique_ptr<WebContents> WebContents::Create(const CreateParams &params) {
+  auto wc = std::make_unique<WebContentsImpl>(params);
+  the_only_web_contents = wc.get();
+  return wc;
+}
+
+WebContentsImpl::WebContentsImpl(const CreateParams &params)
+    : title_(params.main_frame_name_) {
+  int id = latest_rfh_id++;
+  std::unique_ptr<RenderFrameHost> new_rfh(
+      new RenderFrameHostImpl(params.main_frame_name_, id));
+  render_frame_hosts.insert(
+      std::pair<int, RenderFrameHost *>(id, new_rfh.get()));
+  for (auto obs : observers_) {
+    obs->RenderFrameCreated(new_rfh.get());
+  }
+  rfhs_.push_back(std::move(new_rfh));
+}
+
+void WebContentsImpl::AddObserver(WebContentsObserver *observer) {
+  observers_.push_back(observer);
+}
+void WebContentsImpl::RemoveObserver(WebContentsObserver *observer) {
+  std::remove(std::begin(observers_), std::end(observers_), observer);
+}
+
+void WebContentsImpl::DeleteRFH() {
+  for (auto obs : observers_) {
+    obs->RenderFrameDeleted(rfhs_[0].get());
+  }
+  rfhs_.clear();
+}
+
+const std::string &WebContentsImpl::GetTitle() { return title_; }
+
+void SimulateRendererShutdown(int frame_id) {
+  render_frame_hosts.erase(frame_id);
+  the_only_web_contents->DeleteRFH();
+}
diff --git a/examples/chromium-fake-render-frame-host/src/main.rs b/examples/chromium-fake-render-frame-host/src/main.rs
new file mode 100644
index 0000000..d2504dc
--- /dev/null
+++ b/examples/chromium-fake-render-frame-host/src/main.rs
@@ -0,0 +1,73 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use autocxx::prelude::*;
+mod render_frame_host;
+use render_frame_host::RenderFrameHostForWebContents;
+use render_frame_host::RenderFrameHostHandle;
+
+include_cpp! {
+    #include "fake-chromium-header.h"
+    safety!(unsafe) // unsafety policy; see docs
+    generate!("content::WebContents")
+    generate!("content::RenderFrameHost")
+    generate!("content::CreateParams")
+    generate!("SimulateRendererShutdown")
+    subclass!("content::WebContentsObserver",RenderFrameHostForWebContents)
+}
+
+use ffi::ToCppString;
+
+fn main() {
+    // Create some fake toy WebContents.
+    let create_params = ffi::content::CreateParams::new(&"silly-frame".into_cpp()).within_unique_ptr();
+    let mut frame = ffi::content::WebContents::Create(&create_params);
+
+    // This object is a memory-safe handle to a RenderFrameHost.
+    // On creation, we pass it the WebContents, such that it can register
+    // to be informed of the destruction of the RenderFrameHost.
+    // It also happens to store a reference to that WebContents,
+    // so the compiler will prove that this RenderFrameHostHandle
+    // can't outlive the WebContents. That's nice. But currently
+    // it stores an exclusive (a.k.a. mutable) reference, and we may
+    // well want to relax that in future.
+    // (This relates to https://github.com/google/autocxx/issues/622)
+    let mut rfh_handle = RenderFrameHostHandle::from_id(c_int(3), c_int(0), frame.pin_mut());
+
+    // We can directly call methods on the RFH.
+    // (If this were a 'const' method, the `.pin_mut()` wouldn't be necessary).
+    let frame_name = rfh_handle.pin_mut().GetFrameName();
+    println!("Frame name is {}", frame_name.to_str().unwrap());
+
+    {
+        // We can also borrow the RFH and use Rust's borrow checker to ensure
+        // no other code can do so. This also gives us a chance to explicitly
+        // handle the case where the RFH was already destroyed, in case
+        // we want to do something smarter than panicking.
+        let mut rfh_borrowed = rfh_handle
+            .try_borrow_mut()
+            .expect("Oh! The RFH was already destroyed!");
+        // Nobody else can borrow it during this time...
+        //   let mut rfh_borrowed_again = rfh_handle.try_borrow_mut().unwrap();
+        // Gives compile-time error "second mutable borrow occurs here..."
+        let frame_name = rfh_borrowed.pin_mut().GetFrameName();
+        println!("Frame name is {}", frame_name.to_str().unwrap());
+        let frame_name = rfh_borrowed.pin_mut().GetFrameName();
+        println!("Frame name is {}", frame_name.to_str().unwrap());
+
+        // Supposing we end up calling some code deep in the Chrome C++
+        // stack which destroys the RFH whilst it's still borrowed.
+        // That will result in a runtime panic...
+        //  ffi::SimulateRendererShutdown(c_int(0)); // would panic
+    }
+
+    // But let's assume we've now returned to the event loop.
+    // None of the previous borrows still exist. It's perfectly OK to now
+    // delete the RFH.
+    ffi::SimulateRendererShutdown(c_int(0));
+}
diff --git a/examples/chromium-fake-render-frame-host/src/render_frame_host.rs b/examples/chromium-fake-render-frame-host/src/render_frame_host.rs
new file mode 100644
index 0000000..9c2bf51
--- /dev/null
+++ b/examples/chromium-fake-render-frame-host/src/render_frame_host.rs
@@ -0,0 +1,242 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use autocxx::subclass::prelude::*;
+use autocxx::{c_int, PinMut};
+use std::cell::{Ref, RefCell, RefMut};
+use std::ops::Deref;
+use std::pin::Pin;
+use std::rc::Rc;
+
+use crate::ffi;
+
+/// A memory-safe handle to a C++ RenderFrameHost.
+///
+/// This is a toy, hypothetical, example.
+///
+/// Creation: in this sample, the only option is to use [`RenderFrameHostHandle::from_id`]
+/// which corresponds to the equivalent method in C++ `RenderFrameHost`. Unlike
+/// the C++ version, you must pass a WebContents so that Rust wrappers can listen for
+/// destruction events.
+///
+/// The returned handle is memory safe and can be used to access the methods
+/// of [`ffi::content::RenderFrameHost`]. To use such a method, you have three options:
+/// * If you believe there is no chance that the `RenderFrameHost` has been
+///   destroyed, and if the method is const, you can just go ahead and call methods
+///   on this object. As it implements [`std::ops::Deref`], that will just work -
+///   but your code will panic if the `RenderFrameHost` was already destroyed.
+/// * If the method is non-const, you'll have to call `.pin_mut().method()` instead
+//    but otherwise this is functionally identical.
+/// * If you believe that there is a chance that the `RenderFrameHost` was already
+///   destroyed, use [`RenderFrameHostHandle::try_borrow`] or
+///   [`RenderFrameHostHandle::try_borrow_mut`]. This will return
+///   a guard object which guarantees the existence of the `RenderFrameHost`
+///   during its lifetime.
+///
+/// # Performance characteristics
+///
+/// The existence of this object registers an observer with the `WebContents`
+/// and deregisters it on destruction. That is, of course, an overhead, but
+/// that's necessary to keep track of liveness. (A more efficient
+/// implementation would use a single observer for multiple such handles - but
+/// this is a toy implementation).
+///
+/// In addition, each time you extract the value from this
+/// `RenderFrameHostHandle`, a liveness check is performed. This involves
+/// not just a null check but also some reference count manipulation.
+/// If you're going to access the `RenderFrameHost` multiple times, it's
+/// advised that you call [`RenderFrameHostHandle::try_borrow`] or
+/// [`RenderFrameHostHandle::try_borrow_mut`] and then use
+/// the result multiple times. The liveness check for the `RenderFrameHost`
+/// will be performed only once at runtime.
+///
+/// # Destruction of RenderFrameHosts while borrowed
+///
+/// If you have called [`RenderFrameHostHandle::try_borrow`] (or its mutable
+/// equivalent) and still have an outstanding borrow, any code path - via C++
+/// - which results it the destruction of the `RenderFrameHost` will result in
+/// a runtime panic.
+pub struct RenderFrameHostHandle<'wc> {
+    obs: Rc<RefCell<RenderFrameHostForWebContents>>,
+    web_contents: Pin<&'wc mut ffi::content::WebContents>,
+}
+
+impl<'wc> RenderFrameHostHandle<'wc> {
+    /// Create a memory-safe handle to a RenderFrameHost using its
+    /// process ID and frame ID.
+    pub fn from_id(
+        render_process_id: c_int,
+        render_frame_id: c_int,
+        mut web_contents: Pin<&'wc mut ffi::content::WebContents>,
+    ) -> Self {
+        // Instantiate our WebContentsObserver subclass.
+        let obs = RenderFrameHostForWebContents::new_rust_owned(RenderFrameHostForWebContents {
+            rfh: ffi::content::RenderFrameHost::FromId(render_process_id, render_frame_id),
+            cpp_peer: Default::default(),
+        });
+
+        // And now register it.
+        // This nasty line will go away when autocxx is a bit more sophisticated.
+        let superclass_ptr = cast_to_superclass(obs.as_ref().borrow_mut().peer_mut());
+
+        // But this will remain unsafe. cxx policy is that any raw pointer
+        // passed into a C++ function requires an unsafe {} block and that
+        // is sensible. We may of course provide an ergonomic Rust wrapper
+        // around WebContents which provides safe Rust equivalents
+        // (using references or similar rather than pointers) in which case
+        // this unsafe block would go away.
+        unsafe { web_contents.as_mut().AddObserver(superclass_ptr) };
+
+        Self { obs, web_contents }
+    }
+
+    /// Tries to return a mutable reference to the RenderFrameHost.
+    /// Because this requires `self` to be `&mut`, and that lifetime is
+    /// applied to the returned `RenderFrameHost`, the compiler will prevent
+    /// multiple such references existing in Rust at the same time.
+    /// This will return `None` if the RenderFrameHost were already destroyed.
+    pub fn try_borrow_mut<'a>(
+        &'a mut self,
+    ) -> Option<impl PinMut<ffi::content::RenderFrameHost> + 'a> {
+        let ref_mut = self.obs.as_ref().borrow_mut();
+        if ref_mut.rfh.is_null() {
+            None
+        } else {
+            Some(RenderFrameHostRefMut(ref_mut))
+        }
+    }
+
+    /// Tries to return a reference to the RenderFrameHost.
+    /// The compiler will prevent calls to this if anyone has an outstanding
+    /// mutable reference from [`RenderFrameHostHandle::try_borrow_mut`].
+    /// This will return `None` if the RenderFrameHost were already destroyed.
+    #[allow(dead_code)]
+    pub fn try_borrow<'a>(&'a self) -> Option<impl AsRef<ffi::content::RenderFrameHost> + 'a> {
+        let ref_non_mut = self.obs.as_ref().borrow();
+        if ref_non_mut.rfh.is_null() {
+            None
+        } else {
+            Some(RenderFrameHostRef(ref_non_mut))
+        }
+    }
+}
+
+impl<'wc> Drop for RenderFrameHostHandle<'wc> {
+    fn drop(&mut self) {
+        // Unregister our observer.
+        let superclass_ptr = cast_to_superclass(self.obs.as_ref().borrow_mut().peer_mut());
+        unsafe { self.web_contents.as_mut().RemoveObserver(superclass_ptr) };
+    }
+}
+
+impl<'wc> AsRef<ffi::content::RenderFrameHost> for RenderFrameHostHandle<'wc> {
+    fn as_ref(&self) -> &ffi::content::RenderFrameHost {
+        let ref_non_mut = self.obs.as_ref().borrow();
+        // Safety: the .rfh field is guaranteed to be a RenderFrameHost
+        // and we are observing its lifetime so it will be reset to null
+        // if destroyed.
+        unsafe { ref_non_mut.rfh.as_ref() }.expect("This RenderFrameHost was already destroyed")
+    }
+}
+
+impl<'wc> PinMut<ffi::content::RenderFrameHost> for RenderFrameHostHandle<'wc> {
+    fn pin_mut(&mut self) -> Pin<&mut ffi::content::RenderFrameHost> {
+        let ref_mut = self.obs.as_ref().borrow_mut();
+        // Safety: the .rfh field is guaranteed to be a RenderFrameHost
+        // and we are observing its lifetime so it will be reset to null
+        // if destroyed.
+        unsafe { ref_mut.rfh.as_mut().map(|p| Pin::new_unchecked(p)) }
+            .expect("This RenderFrameHost was already destroyed")
+    }
+}
+
+impl<'wc> Deref for RenderFrameHostHandle<'wc> {
+    type Target = ffi::content::RenderFrameHost;
+    fn deref(&self) -> &Self::Target {
+        self.as_ref()
+    }
+}
+
+#[doc(hidden)]
+struct RenderFrameHostRefMut<'a>(RefMut<'a, RenderFrameHostForWebContents>);
+
+#[doc(hidden)]
+struct RenderFrameHostRef<'a>(Ref<'a, RenderFrameHostForWebContents>);
+
+impl<'a> AsRef<ffi::content::RenderFrameHost> for RenderFrameHostRef<'a> {
+    fn as_ref(&self) -> &ffi::content::RenderFrameHost {
+        // Safety:
+        // Creation precondition is that self.0.rfh is not null
+        // and it can't be destroyed whilst this borrow exists.
+        unsafe { self.0.rfh.as_ref().unwrap() }
+    }
+}
+
+impl<'a> PinMut<ffi::content::RenderFrameHost> for RenderFrameHostRefMut<'a> {
+    fn pin_mut(&mut self) -> Pin<&mut ffi::content::RenderFrameHost> {
+        // Safety:
+        // Creation precondition is that self.0.rfh is not null
+        // and it can't be destroyed whilst this borrow exists.
+        unsafe { Pin::new_unchecked(self.0.rfh.as_mut().unwrap()) }
+    }
+}
+
+impl<'a> AsRef<ffi::content::RenderFrameHost> for RenderFrameHostRefMut<'a> {
+    fn as_ref(&self) -> &ffi::content::RenderFrameHost {
+        // Safety:
+        // Creation precondition is that self.0.rfh is not null
+        // and it can't be destroyed whilst this borrow exists.
+        unsafe { self.0.rfh.as_ref().unwrap() }
+    }
+}
+
+impl<'a> Deref for RenderFrameHostRef<'a> {
+    type Target = ffi::content::RenderFrameHost;
+    fn deref(&self) -> &Self::Target {
+        self.as_ref()
+    }
+}
+
+impl<'a> Deref for RenderFrameHostRefMut<'a> {
+    type Target = ffi::content::RenderFrameHost;
+    fn deref(&self) -> &Self::Target {
+        self.as_ref()
+    }
+}
+
+#[is_subclass(superclass("content::WebContentsObserver"))]
+#[doc(hidden)]
+pub struct RenderFrameHostForWebContents {
+    rfh: *mut ffi::content::RenderFrameHost,
+}
+
+impl ffi::content::WebContentsObserver_methods for RenderFrameHostForWebContents {
+    unsafe fn RenderFrameDeleted(&mut self, destroyed_rfh: *mut ffi::content::RenderFrameHost) {
+        if self.rfh == destroyed_rfh {
+            self.rfh = std::ptr::null_mut()
+        }
+    }
+}
+
+fn cast_to_superclass(
+    obs: Pin<&mut ffi::RenderFrameHostForWebContentsCpp>,
+) -> *mut ffi::content::WebContentsObserver {
+    // This horrid code will all go away once we implement
+    // https://github.com/google/autocxx/issues/592; safe wrappers will
+    // be automatically generated to allow upcasting to superclasses.
+    // NB this code is probably actually _wrong_ too meanwhile; we need to cast
+    // on the C++ side.
+    let subclass_obs_ptr =
+        unsafe { Pin::into_inner_unchecked(obs) } as *mut ffi::RenderFrameHostForWebContentsCpp;
+    unsafe {
+        std::mem::transmute::<
+            *mut ffi::RenderFrameHostForWebContentsCpp,
+            *mut ffi::content::WebContentsObserver,
+        >(subclass_obs_ptr)
+    }
+}
diff --git a/examples/llvm/Cargo.toml b/examples/llvm/Cargo.toml
new file mode 100644
index 0000000..d8806c8
--- /dev/null
+++ b/examples/llvm/Cargo.toml
@@ -0,0 +1,21 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+[package]
+name = "autocxx-llvm-example"
+version = "0.1.0"
+authors = ["Adrian Taylor <adetaylor@chromium.org>"]
+edition = "2021"
+
+[dependencies]
+cxx = "1.0.54"
+autocxx = { path = "../..", version="0.17.2" }
+
+[build-dependencies]
+autocxx-build = { path = "../../gen/build", version="0.17.2" }
+miette = { version="4.3", features = [ "fancy" ] }
diff --git a/examples/llvm/build.rs b/examples/llvm/build.rs
new file mode 100644
index 0000000..1bb82ce
--- /dev/null
+++ b/examples/llvm/build.rs
@@ -0,0 +1,23 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::path::PathBuf;
+fn main() -> miette::Result<()> {
+    let mut b = autocxx_build::Builder::new(
+        "src/lib.rs",
+        &[
+            PathBuf::from("/usr/include/llvm-13"),
+            PathBuf::from("/usr/include/llvm-c-13"),
+        ],
+    )
+    .build()?;
+
+    b.flag_if_supported("-std=c++14").compile("llvm");
+    println!("cargo:rerun-if-changed=src/lib.rs");
+    Ok(())
+}
diff --git a/examples/llvm/src/lib.rs b/examples/llvm/src/lib.rs
new file mode 100644
index 0000000..bd18880
--- /dev/null
+++ b/examples/llvm/src/lib.rs
@@ -0,0 +1,23 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use autocxx::prelude::*; // use all the main autocxx functions
+
+include_cpp! {
+    #include "llvm/Support/MemoryBuffer.h"
+    safety!(unsafe)
+    generate!("llvm::MemoryBuffer")
+}
+
+// Simply re-export the MemoryBuffer API to users of this library.
+// Generally speaking, the APIs generated by autocxx (or similar tools)
+// still contain C++-isms, and it's wise to consider making idiomatic
+// Rust wrappers instead of doing this.
+pub use ffi::llvm::MemoryBuffer;
+
+// It would be advisable to add tests here.
diff --git a/examples/non-trivial-type-on-stack/Cargo.toml b/examples/non-trivial-type-on-stack/Cargo.toml
new file mode 100644
index 0000000..ff227d4
--- /dev/null
+++ b/examples/non-trivial-type-on-stack/Cargo.toml
@@ -0,0 +1,21 @@
+# Copyright 2022 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+[package]
+name = "autocxx-non-trivial-type-on-stack-example"
+version = "0.1.0"
+authors = ["Adrian Taylor <adetaylor@chromium.org>"]
+edition = "2021"
+
+[dependencies]
+cxx = "1.0.54"
+autocxx = { path = "../..", version="0.22.0" }
+
+[build-dependencies]
+autocxx-build = { path = "../../gen/build", version="0.22.0" }
+miette = { version="4.3", features = [ "fancy" ] }
diff --git a/examples/non-trivial-type-on-stack/build.rs b/examples/non-trivial-type-on-stack/build.rs
new file mode 100644
index 0000000..f83a228
--- /dev/null
+++ b/examples/non-trivial-type-on-stack/build.rs
@@ -0,0 +1,17 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() -> miette::Result<()> {
+    let path = std::path::PathBuf::from("src");
+    let mut b = autocxx_build::Builder::new("src/main.rs", &[&path]).build()?;
+    b.flag_if_supported("-std=c++14")
+        .compile("autocxx-non-trivial-type-on-stack-example");
+    println!("cargo:rerun-if-changed=src/main.rs");
+    println!("cargo:rerun-if-changed=src/cpp.h");
+    Ok(())
+}
diff --git a/examples/non-trivial-type-on-stack/src/cpp.h b/examples/non-trivial-type-on-stack/src/cpp.h
new file mode 100644
index 0000000..9cb6502
--- /dev/null
+++ b/examples/non-trivial-type-on-stack/src/cpp.h
@@ -0,0 +1,24 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#pragma once
+#include <iostream>
+
+class MessageBuffer {
+public:
+  // std::string is not a trivial type because in some STL implementations
+  // it may contain a self-referential pointer.
+  void add_blurb(std::string blurb) {
+    message += blurb;
+  }
+  std::string get() const {
+    return message;
+  }
+private:
+  std::string message;
+};
diff --git a/examples/non-trivial-type-on-stack/src/main.rs b/examples/non-trivial-type-on-stack/src/main.rs
new file mode 100644
index 0000000..32dcdd7
--- /dev/null
+++ b/examples/non-trivial-type-on-stack/src/main.rs
@@ -0,0 +1,30 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use autocxx::prelude::*;
+
+include_cpp! {
+    // C++ headers we want to include.
+    #include "cpp.h"
+    safety!(unsafe)
+    // A non-trivial C++ type
+    generate!("MessageBuffer")
+}
+
+fn main() {
+    // Put the non-trivial C++ type on the Rust stack.
+    moveit! { let mut msg = ffi::MessageBuffer::new(); }
+    // Call methods on it.
+    msg.as_mut().add_blurb("Hello");
+    msg.as_mut().add_blurb(" world!");
+
+    assert_eq!(
+        msg.get().as_ref().unwrap().to_string_lossy(),
+        "Hello world!"
+    );
+}
diff --git a/examples/pod/Cargo.toml b/examples/pod/Cargo.toml
new file mode 100644
index 0000000..71bd5a0
--- /dev/null
+++ b/examples/pod/Cargo.toml
@@ -0,0 +1,21 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+[package]
+name = "autocxx-pod-example"
+version = "0.1.0"
+authors = ["Adrian Taylor <adetaylor@chromium.org>"]
+edition = "2021"
+
+[dependencies]
+cxx = "1.0.54"
+autocxx = { path = "../..", version="0.22.0" }
+
+[build-dependencies]
+autocxx-build = { path = "../../gen/build", version="0.22.0" }
+miette = { version="4.3", features = [ "fancy" ] }
diff --git a/examples/pod/build.rs b/examples/pod/build.rs
new file mode 100644
index 0000000..a6bd95c
--- /dev/null
+++ b/examples/pod/build.rs
@@ -0,0 +1,17 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() -> miette::Result<()> {
+    let path = std::path::PathBuf::from("src");
+    let mut b = autocxx_build::Builder::new("src/main.rs", &[&path]).build()?;
+    b.flag_if_supported("-std=c++14")
+        .compile("autocxx-pod-example");
+    println!("cargo:rerun-if-changed=src/main.rs");
+    println!("cargo:rerun-if-changed=src/cpp.h");
+    Ok(())
+}
diff --git a/examples/pod/src/cpp.h b/examples/pod/src/cpp.h
new file mode 100644
index 0000000..94d1466
--- /dev/null
+++ b/examples/pod/src/cpp.h
@@ -0,0 +1,27 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#pragma once
+#include <iostream>
+
+struct Point {
+  int x;
+  int y;
+};
+
+class Rect {
+public:
+  Point top_left;
+  Point bottom_right;
+  int width() const { return bottom_right.x - top_left.x; }
+  int height() const { return bottom_right.y - top_left.y; }
+};
+
+inline void print_point(Point p) {
+  std::cout << "(" << p.x << ", " << p.y << ")\n";
+}
diff --git a/examples/pod/src/main.rs b/examples/pod/src/main.rs
new file mode 100644
index 0000000..7a8b659
--- /dev/null
+++ b/examples/pod/src/main.rs
@@ -0,0 +1,40 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use autocxx::prelude::*;
+
+include_cpp! {
+    // C++ headers we want to include.
+    #include "cpp.h"
+    // Safety policy. We are marking that this whole C++ inclusion is unsafe
+    // which means the functions themselves do not need to be marked
+    // as unsafe. Other policies are possible.
+    safety!(unsafe)
+    // What types and functions we want to generate
+    generate_pod!("Rect")
+    generate!("print_point")
+}
+
+use ffi::{Point, Rect};
+
+// A simple example dealing with plain-old-data types.
+
+fn main() {
+    let r = Rect {
+        top_left: Point { x: 3, y: 3 },
+        bottom_right: Point { x: 12, y: 15 },
+    };
+    // r.width() and r.height() return an autocxx::c_int
+    // which we need to unpackage. It is hoped that one day cxx will
+    // natively support 'int' and friends, and that won't be necessary.
+    let center = Point {
+        x: r.top_left.x + r.width().0 / 2,
+        y: r.top_left.y + r.height().0 / 2,
+    };
+    ffi::print_point(center);
+}
diff --git a/examples/s2/Cargo.toml b/examples/s2/Cargo.toml
new file mode 100644
index 0000000..994a381
--- /dev/null
+++ b/examples/s2/Cargo.toml
@@ -0,0 +1,23 @@
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+[package]
+name = "autocxx-s2-example"
+version = "0.1.0"
+authors = ["Adrian Taylor <adetaylor@chromium.org>"]
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+cxx = "1.0.54"
+autocxx = { path = "../..", version="0.22.0" }
+
+[build-dependencies]
+autocxx-build = { path = "../../gen/build", version="0.22.0" }
+miette = { version="4.3", features = [ "fancy" ] }
diff --git a/examples/s2/README.md b/examples/s2/README.md
new file mode 100644
index 0000000..36a56ca
--- /dev/null
+++ b/examples/s2/README.md
@@ -0,0 +1,5 @@
+To build this example:
+* `git submodule update --init --recursive s2geometry`
+* `cargo run`
+
+Thanks to @nside for inspiring this example.
diff --git a/examples/s2/build.rs b/examples/s2/build.rs
new file mode 100644
index 0000000..e61c1af
--- /dev/null
+++ b/examples/s2/build.rs
@@ -0,0 +1,20 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() -> miette::Result<()> {
+    // It's necessary to use an absolute path here because the
+    // C++ codegen and the macro codegen appears to be run from different
+    // working directories.
+    let path = std::path::PathBuf::from("s2geometry/src");
+    let path2 = std::path::PathBuf::from("src");
+    let mut b = autocxx_build::Builder::new("src/main.rs", &[&path, &path2]).build()?;
+    b.flag_if_supported("-std=c++14")
+        .compile("autocxx-s2-example");
+    println!("cargo:rerun-if-changed=src/main.rs");
+    Ok(())
+}
diff --git a/examples/s2/s2geometry b/examples/s2/s2geometry
new file mode 160000
index 0000000..0c4c460
--- /dev/null
+++ b/examples/s2/s2geometry
@@ -0,0 +1 @@
+Subproject commit 0c4c460bdfe696da303641771f9def900b3e440f
diff --git a/examples/s2/src/extras.h b/examples/s2/src/extras.h
new file mode 100644
index 0000000..927a30d
--- /dev/null
+++ b/examples/s2/src/extras.h
@@ -0,0 +1,27 @@
+// Copyright 2020 Google LLC
+//  
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//  
+//    https://www.apache.org/licenses/LICENSE-2.0 
+//  
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include "s2/r2.h"
+#include <sstream>
+
+// autocxx isn't yet smart enough to do anything with the R2Point
+// structure, so here we've manually made a cheeky little API to
+// do something useful with it.
+inline std::string describe_point(R2Point pt) {
+    std::ostringstream oss;
+    oss << pt.x() << ", " << pt.y();
+    return oss.str();
+}
diff --git a/examples/s2/src/main.rs b/examples/s2/src/main.rs
new file mode 100644
index 0000000..141b80e
--- /dev/null
+++ b/examples/s2/src/main.rs
@@ -0,0 +1,53 @@
+// Copyright 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use autocxx::prelude::*;
+
+include_cpp! {
+    // C++ headers we want to include.
+    #include "s2/r2rect.h"
+    #include "extras.h"
+    // Safety policy. We are marking that this whole C++ inclusion is unsafe
+    // which means the functions themselves do not need to be marked
+    // as unsafe. Other policies are possible.
+    safety!(unsafe)
+    // What types and functions we want to generate
+    generate!("R1Interval")
+    generate!("R2Rect")
+    generate!("describe_point")
+}
+
+// Everything that we care about is inlined, so we don't have to do
+// anything fancy to build or link any external code.
+fn main() {
+    // Create a couple of R1Intervals using their pre-existing C++
+    // constructors. Actually these will be cxx::UniquePtr<R1Interval>s.
+    let i1 = ffi::R1Interval::new(1.0f64, 2.0f64).within_unique_ptr();
+    let i2 = ffi::R1Interval::new(5.0f64, 6.0f64).within_unique_ptr();
+    // Create a rect, passing references to the intervals.
+    // Note this is 'new1' because R2Rect has multiple
+    // overloaded constructors. 'cargo expand', `cargo doc`
+    // or a rust-analyzer IDE is useful here.
+    let r = ffi::R2Rect::new1(&i1, &i2).within_unique_ptr();
+    // Call a method on one of these objects. As it happens,
+    // this returns a
+    // UniquePtr< ... opaque object representing a point ...>.
+    let center = r.GetCenter();
+    // As the object is too complex for autocxx to understand,
+    // we can't do much with it except to send it into other
+    // C++ APIs. We'll make our own which describes the point.
+    // This will return a std::string, which autocxx will
+    // convert to a UniquePtr<CxxString>. We can convert that
+    // back to a Rust string and print it, so long as we
+    // take care to decide how to deal with non-UTF8
+    // characters (hence the unwrap).
+    println!(
+        "Center of rectangle is {}",
+        ffi::describe_point(center).to_str().unwrap()
+    );
+}
diff --git a/examples/steam-mini/Cargo.toml b/examples/steam-mini/Cargo.toml
new file mode 100644
index 0000000..b292f25
--- /dev/null
+++ b/examples/steam-mini/Cargo.toml
@@ -0,0 +1,23 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+[package]
+name = "autocxx-steam-example"
+version = "0.1.0"
+authors = ["Adrian Taylor <adetaylor@chromium.org>"]
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+cxx = "1.0.54"
+autocxx = { path = "../..", version="0.22.0" }
+
+[build-dependencies]
+autocxx-build = { path = "../../gen/build", version="0.22.0" }
+miette = { version="4.3", features = [ "fancy" ] }
diff --git a/examples/steam-mini/README.md b/examples/steam-mini/README.md
new file mode 100644
index 0000000..325c899
--- /dev/null
+++ b/examples/steam-mini/README.md
@@ -0,0 +1,2 @@
+This example is supposed to simulate something a bit like the Steam API,
+where you're given a pointer to a collection of virtual methods.
diff --git a/examples/steam-mini/build.rs b/examples/steam-mini/build.rs
new file mode 100644
index 0000000..d9b3c68
--- /dev/null
+++ b/examples/steam-mini/build.rs
@@ -0,0 +1,17 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() -> miette::Result<()> {
+    let path = std::path::PathBuf::from("steam/src");
+    let mut b = autocxx_build::Builder::new("src/main.rs", &[&path]).build()?;
+    b.flag_if_supported("-std=c++14")
+        .file("steam/src/steam.cc")
+        .compile("autocxx-steam-example");
+    println!("cargo:rerun-if-changed=src/main.rs");
+    Ok(())
+}
diff --git a/examples/steam-mini/src/main.rs b/examples/steam-mini/src/main.rs
new file mode 100644
index 0000000..e5d6e64
--- /dev/null
+++ b/examples/steam-mini/src/main.rs
@@ -0,0 +1,65 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use autocxx::prelude::*;
+
+include_cpp! {
+    // C++ headers we want to include.
+    #include "steam.h"
+    // Safety policy. We are marking that this whole C++ inclusion is unsafe
+    // which means the functions themselves do not need to be marked
+    // as unsafe. Other policies are possible.
+    safety!(unsafe)
+    // What types and functions we want to generate
+    generate!("GetSteamEngine")
+    generate!("IEngine")
+}
+
+fn main() {
+    // The "Steam" API gives us a void* on which we call virtual functions.
+    // This is a void*.
+    let steam_engine = ffi::GetSteamEngine();
+    // We need to know three things about this void*:
+    // 1. What is it? We know from the (fake) Steam documentation that it's
+    //    an IEngine*
+    // 2. Do we gain ownership of it? i.e. is it our responsibility to
+    //    destroy it?
+    // 3. If not, C++ presumably continues to own it. Does C++ ever destroy
+    //    it?
+    // None of these things are really encoded in the nature of a void*
+    // so you have to figure them out from the documentation.
+    //
+    // In this case, the first is easy:
+    let steam_engine = steam_engine as *mut ffi::IEngine;
+    //
+    // You then need to figure out how to expose it in Rust. Ideally, any
+    // such lifetime invariants would be handled by the compiler.
+    // If C++ is passing ownership of this object to us, and we have the
+    // prerogative to destroy it whenever we wish, then
+    // simply use [`cxx::UniquePtr::from_raw`]. If it goes out of scope in
+    // Rust the underlying C++ object will be deleted.
+    //
+    // Let's assume life is more complicated, and we must never destroy this
+    // object (because it's owned by C++). In that case, we ideally want
+    // to convert the pointer into a Rust reference with the lifetime of
+    // the program.
+    //
+    // We also have to promise to Rust that it'll never move in memory.
+    // C++ doesn't do that, so that's OK.
+    let mut steam_engine = unsafe { std::pin::Pin::new_unchecked(&mut *steam_engine) };
+    // Now we have steam_engine which is a Pin<&mut SteamEngine>
+    // Each time we call a method we need to add `as_mut()`
+    // as per the pattern explained in
+    // https://doc.rust-lang.org/std/pin/struct.Pin.html#method.as_mut
+    steam_engine
+        .as_mut()
+        .ConnectToGlobalUser(autocxx::c_int(12));
+    steam_engine
+        .as_mut()
+        .DisconnectGlobalUser(autocxx::c_int(12));
+}
diff --git a/examples/steam-mini/steam/src/steam.cc b/examples/steam-mini/steam/src/steam.cc
new file mode 100644
index 0000000..2c45488
--- /dev/null
+++ b/examples/steam-mini/steam/src/steam.cc
@@ -0,0 +1,28 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#include <iostream>
+#include "steam.h"
+
+// This is a simulation of _something like_ the way the steam API works.
+// None of this code is really from Steam.
+
+class SteamEngine : public IEngine {
+    int ConnectToGlobalUser(int user_id) {
+        std::cout << "ConnectToGlobalUser, passed " << user_id << std::endl;
+        return 42;
+    }
+    void DisconnectGlobalUser(int user_id) {
+        std::cout << "DisconnectGlobalUser, passed " << user_id << std::endl;
+    }
+};
+
+void* GetSteamEngine() {
+    return new SteamEngine();
+}
+
diff --git a/examples/steam-mini/steam/src/steam.h b/examples/steam-mini/steam/src/steam.h
new file mode 100644
index 0000000..f07aee3
--- /dev/null
+++ b/examples/steam-mini/steam/src/steam.h
@@ -0,0 +1,19 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#pragma once
+
+// This is a simulation of _something like_ the way the steam API works.
+
+class IEngine {
+public:
+	virtual int ConnectToGlobalUser(int) = 0;
+    virtual void DisconnectGlobalUser(int user_id) = 0;
+};
+
+void* GetSteamEngine(); // return an IEngine*
diff --git a/examples/subclass/Cargo.toml b/examples/subclass/Cargo.toml
new file mode 100644
index 0000000..8a01205
--- /dev/null
+++ b/examples/subclass/Cargo.toml
@@ -0,0 +1,27 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+[package]
+name = "autocxx-subclass-example"
+version = "0.1.0"
+authors = ["Adrian Taylor <adetaylor@chromium.org>"]
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+cxx = "1.0.54"
+autocxx = { path = "../..", version="0.22.0" }
+uwuify = "0.2.2"
+textwrap = "0.14"
+fastrand = "1.5.0"
+
+[build-dependencies]
+autocxx-build = { path = "../../gen/build", version="0.22.0" }
+regex = "1.5.4"
+miette = { version="4.3", features = [ "fancy" ] }
diff --git a/examples/subclass/README.md b/examples/subclass/README.md
new file mode 100644
index 0000000..b46d001
--- /dev/null
+++ b/examples/subclass/README.md
@@ -0,0 +1 @@
+This example shows Rust types 'inheriting' from C++ subclasses.
diff --git a/examples/subclass/build.rs b/examples/subclass/build.rs
new file mode 100644
index 0000000..b41e924
--- /dev/null
+++ b/examples/subclass/build.rs
@@ -0,0 +1,93 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() -> miette::Result<()> {
+    let path = std::path::PathBuf::from("src");
+    let mut b = autocxx_build::Builder::new("src/main.rs", &[&path])
+        .auto_allowlist(true)
+        .build()?;
+    b.flag_if_supported("-std=c++17")
+        .file("src/messages.cc")
+        .compile("autocxx-subclass-example");
+    println!("cargo:rerun-if-changed=src/main.rs");
+    println!("cargo:rerun-if-changed=src/messages.cc");
+    println!("cargo:rerun-if-changed=src/messages.h");
+
+    // The following line is *unrelated* to autocxx builds and is
+    // just designed to ensure that example code doesn't get out of sync
+    // from copies in comments.
+    ensure_comments_match_real_code(&std::path::PathBuf::from("src/main.rs"));
+    Ok(())
+}
+
+use std::fs::File;
+use std::io::BufRead;
+use std::io::BufReader;
+use std::io::Lines;
+use std::path::Path;
+
+enum CommentMatcherState {
+    Searching,
+    EatingBacktickLine(Lines<BufReader<File>>),
+    SearchingForFirstLine(Lines<BufReader<File>>),
+    Found(Lines<BufReader<File>>),
+}
+
+fn ensure_comments_match_real_code(rs_file: &Path) {
+    use regex::Regex;
+    let start_re = Regex::new(r"// .*from ([\w/]+\.\w+).*").unwrap();
+    let strip_comment_re = Regex::new(r"// (.*)").unwrap();
+    let file = File::open(rs_file).unwrap();
+    let lines = BufReader::new(file).lines();
+    let mut state = CommentMatcherState::Searching;
+    for line in lines {
+        let line = line.unwrap();
+        state = match state {
+            CommentMatcherState::Searching => match start_re.captures(&line) {
+                Some(captures) => {
+                    let fname = captures.get(1).unwrap().as_str();
+                    let srcfile = File::open(fname).unwrap();
+                    let srclines = BufReader::new(srcfile).lines();
+                    CommentMatcherState::EatingBacktickLine(srclines)
+                }
+                None => CommentMatcherState::Searching,
+            },
+            CommentMatcherState::EatingBacktickLine(srclines) => {
+                CommentMatcherState::SearchingForFirstLine(srclines)
+            }
+            CommentMatcherState::SearchingForFirstLine(mut srclines) => {
+                match strip_comment_re.captures(&line) {
+                    Some(captures) => {
+                        let mut found = false;
+                        while !found {
+                            let srcline = srclines.next().unwrap().unwrap();
+                            found = captures.get(1).unwrap().as_str() == srcline;
+                        }
+                        CommentMatcherState::Found(srclines)
+                    }
+                    None => CommentMatcherState::Searching,
+                }
+            }
+            CommentMatcherState::Found(mut srclines) => {
+                if line == "// ```" {
+                    CommentMatcherState::Searching
+                } else {
+                    match strip_comment_re.captures(&line) {
+                        Some(captures) => {
+                            let actual = captures.get(1).unwrap().as_str();
+                            let expected = srclines.next().unwrap().unwrap();
+                            assert_eq!(expected, actual);
+                            CommentMatcherState::Found(srclines)
+                        }
+                        None => CommentMatcherState::Searching,
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/examples/subclass/src/billy.rs b/examples/subclass/src/billy.rs
new file mode 100644
index 0000000..5defe1b
--- /dev/null
+++ b/examples/subclass/src/billy.rs
@@ -0,0 +1,20 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub(crate) static SHAKESPEARE_QUOTES: [&str; 10] = [
+    "All that glitters is not gold",
+    "Hell is empty and all the devils are here.",
+    "Good night, good night! parting is such sweet sorrow, That I shall say good night till it be morrow.",
+    "These violent delights have violent ends...",
+    "Something is rotten in the state of Denmark.",
+    "Love all, trust a few, do wrong to none.",
+    "The lady doth protest too much, methinks.",
+    "Brevity is the soul of wit.",
+    "Uneasy lies the head that wears a crown.",
+    "Now is the winter of our discontent.",
+];
diff --git a/examples/subclass/src/main.rs b/examples/subclass/src/main.rs
new file mode 100644
index 0000000..2841598
--- /dev/null
+++ b/examples/subclass/src/main.rs
@@ -0,0 +1,145 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This example shows some Rust subclasses of C++ classes.
+
+mod billy;
+mod uwu;
+
+use autocxx::prelude::*;
+use autocxx::subclass::prelude::*;
+use cxx::CxxString;
+use std::cell::RefCell;
+use std::rc::Rc;
+
+include_cpp! {
+    #include "messages.h"
+    safety!(unsafe) // unsafety policy; see docs
+}
+
+// Here's the definition of MessageDisplayer from src/messages.h:
+// ```cpp
+// class MessageDisplayer {
+// public:
+//     virtual void display_message(const std::string& message) const = 0;
+//     virtual ~MessageDisplayer() {};
+// };
+// ```
+// The following lines define a subclass of MessageDisplayer.
+// See the main function at the bottom for how this subclass
+// is instantiated.
+
+#[is_subclass(superclass("MessageDisplayer"))]
+#[derive(Default)]
+pub struct UwuDisplayer {}
+
+impl ffi::MessageDisplayer_methods for UwuDisplayer {
+    fn display_message(&self, msg: &CxxString) {
+        let uwu = uwu::uwu(msg.to_str().unwrap());
+        println!("{}", uwu);
+    }
+}
+
+// And here's a different pure virtual class.
+// Here's its definition from src/messages.h:
+// ```cpp
+// class MessageProducer {
+// public:
+//     virtual std::string get_message() const = 0;
+//     virtual ~MessageProducer() {};
+// };
+// ```
+// This one is notable only in that the interface of the C++ class
+// involves std::string, yet in Rust the subclass uses
+// std::unique_ptr<std::string> (for all the normal reasons in autocxx -
+// for now, at least, we can't hold non-trivial C++ objects on the Rust stack.)
+// All the boxing and unboxing is done automatically by autocxx layers.
+
+#[is_subclass(superclass("MessageProducer"))]
+#[derive(Default)]
+pub struct QuoteProducer;
+
+// Here we've chosen to have an explicit constructor instead rather than deriving
+// from CppSubclassDefault. It's functionally the same.
+impl QuoteProducer {
+    fn new() -> Rc<RefCell<Self>> {
+        Self::new_rust_owned(Self::default())
+    }
+}
+
+impl ffi::MessageProducer_methods for QuoteProducer {
+    fn get_message(&self) -> cxx::UniquePtr<CxxString> {
+        use ffi::ToCppString;
+        billy::SHAKESPEARE_QUOTES[fastrand::usize(0..billy::SHAKESPEARE_QUOTES.len())].into_cpp()
+    }
+}
+
+// Here's another subclass of the same 'displayer' class.
+// This one is more complex in two ways.
+//
+// First, we actually want to store some data here in our subclass.
+// That means we can't just allocate ourselves with Default::default().
+// And that means we need to be aware of the cpp_peer field which is
+// added by the #[subclass] macro.
+//
+// Second, we're going to simulate the observer/listener type pattern
+// in C++ where a const* is used to send messages around a codebase yet
+// recipients need to react by mutating themselves or otherwise actively
+// doing stuff. In C++ you'd probably need a const_cast. Here we use
+// interior mutability.
+
+#[is_subclass(superclass("MessageDisplayer"))]
+pub struct BoxDisplayer {
+    message_count: RefCell<usize>,
+}
+
+impl BoxDisplayer {
+    fn new() -> Rc<RefCell<Self>> {
+        Self::new_rust_owned(Self {
+            // As we're allocating this class ourselves instead of using [`Default`]
+            // we need to initialize the `cpp_peer` member ourselves. This member is
+            // inserted by the `#[is_subclass]` annotation. autocxx will
+            // later use this to store a pointer back to the C++ peer.
+            cpp_peer: Default::default(),
+            message_count: RefCell::new(1usize),
+        })
+    }
+}
+
+impl ffi::MessageDisplayer_methods for BoxDisplayer {
+    fn display_message(&self, msg: &CxxString) {
+        let msg = textwrap::fill(msg.to_str().unwrap(), 70);
+        let horz_line = std::iter::repeat("#").take(74).collect::<String>();
+        println!("{}", horz_line);
+        let msgmsg = format!("Message {}", self.message_count.borrow());
+        self.message_count.replace_with(|old| *old + 1usize);
+        println!("# {:^70} #", msgmsg);
+        println!("{}", horz_line);
+        for l in msg.lines() {
+            println!("# {:^70} #", l);
+        }
+        println!("{}", horz_line);
+    }
+}
+
+fn main() {
+    ffi::register_cpp_thingies();
+    // Construct a Rust-owned UwuDisplayer. We can also construct
+    // a C++-owned or self-owned subclass - see docs for `CppSubclass`.
+    let uwu = UwuDisplayer::default_rust_owned();
+    // The next line casts the &UwuDisplayerCpp to a &MessageDisplayer.
+    ffi::register_displayer(uwu.as_ref().borrow().as_ref());
+    // Constructs in just the same way as the first one, but using
+    // our explicit constructor.
+    let boxd = BoxDisplayer::new();
+    ffi::register_displayer(boxd.as_ref().borrow().as_ref());
+    let shakespeare = QuoteProducer::new();
+    ffi::register_producer(shakespeare.as_ref().borrow().as_ref());
+    ffi::run_demo();
+    ffi::run_demo();
+}
diff --git a/examples/subclass/src/messages.cc b/examples/subclass/src/messages.cc
new file mode 100644
index 0000000..4d24aab
--- /dev/null
+++ b/examples/subclass/src/messages.cc
@@ -0,0 +1,70 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This example shows Rust subclasses of C++ classes.
+// See messages.h and main.rs for most of the interesting code.
+
+#include "messages.h"
+#include <ctime>
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include <functional>
+ 
+class CppExampleProducer : public MessageProducer {
+public:
+    CppExampleProducer() {}
+    std::string get_message() const {
+        std::time_t result = std::time(nullptr);
+        std::ostringstream st;
+        st << std::asctime(std::localtime(&result))
+           << result << " seconds since the Epoch";
+        return st.str();
+    }
+};
+
+class CppExampleDisplayer : public MessageDisplayer {
+public:
+    CppExampleDisplayer() {}
+    void display_message(const std::string& msg) const {
+        std::cout << "Message: " << msg << std::endl;
+    }
+};
+
+std::vector<std::reference_wrapper<const MessageProducer>> producers;
+std::vector<std::reference_wrapper<const MessageDisplayer>> displayers;
+CppExampleProducer cpp_producer;
+CppExampleDisplayer cpp_displayer;
+
+
+// Maybe we should use a language which tracks lifetimes
+// better than this. If only such a language existed.
+void register_displayer(const MessageDisplayer& displayer) {
+    displayers.push_back(displayer);
+}
+
+void register_producer(const MessageProducer& producer) {
+    producers.push_back(producer);
+}
+
+void register_cpp_thingies() {
+    register_producer(cpp_producer);
+    register_displayer(cpp_displayer);
+}
+
+void run_demo() {
+    for (auto& producer: producers) {
+        auto msg = producer.get().get_message();
+        for (auto& displayer: displayers) {
+            displayer.get().display_message(msg);
+            std::cout << std::endl;
+        }
+        std::cout << std::endl;
+    }
+}
+
diff --git a/examples/subclass/src/messages.h b/examples/subclass/src/messages.h
new file mode 100644
index 0000000..02ff248
--- /dev/null
+++ b/examples/subclass/src/messages.h
@@ -0,0 +1,33 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This example shows Rust subclasses of C++ classes.
+// Here are the C++ classes which we're subclassing.
+
+#pragma once
+
+#include <string>
+#include <memory>
+
+class MessageProducer {
+public:
+    virtual std::string get_message() const = 0;
+    virtual ~MessageProducer() {};
+};
+
+class MessageDisplayer {
+public:
+    virtual void display_message(const std::string& message) const = 0;
+    virtual ~MessageDisplayer() {};
+};
+
+void register_cpp_thingies();
+void register_producer(const MessageProducer& producer);
+void register_displayer(const MessageDisplayer& displayer);
+
+void run_demo();
diff --git a/examples/subclass/src/uwu.rs b/examples/subclass/src/uwu.rs
new file mode 100644
index 0000000..ce02510
--- /dev/null
+++ b/examples/subclass/src/uwu.rs
@@ -0,0 +1,17 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+pub(crate) fn uwu(msg: &str) -> String {
+    uwuifier::uwuify_str_sse(msg)
+}
+
+#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+pub(crate) fn uwu(_msg: &str) -> String {
+    "uwuification is unavailable for this pwatform :(".to_string()
+}