docs
Loading...
Searching...
No Matches
HolderTraits< H, typename >

#include <Ultralight/HolderTraits.h>

Overview

template<typename H, typename = void>
struct ultralight::HolderTraits< H, typename >

Traits template that lets the library hold objects through custom smart pointers.

Specializing HolderTraits teaches the library how to inspect and unwrap your engine's smart pointers.

Standard smart pointers like std::shared_ptr and std::unique_ptr work automatically without extra setup. You only need to specialize this template when integrating custom smart pointers from your application or engine.

This example specializes HolderTraits for an engine reference-counted pointer and binds a member function:

template <typename T>
struct ultralight::HolderTraits<MyRef<T>> {
using element_type = T;
static constexpr HolderKind kind = HolderKind::Shared;
static T* Get(const MyRef<T>& holder) { return holder.get(); }
};
MyRef<Player> player = SpawnPlayer();
app["jump"] = js::Bind(player, &Player::Jump);
auto Bind(T *instance, M method)
Bind a member function to an instance without writing a lambda.
Definition API.h:1435
HolderKind
Whether a holder shares ownership of a bound-class instance or owns it alone.
Definition HolderTraits.h:16
@ Shared
Copies share ownership (eg, RefPtr), or the instance is never destroyed (js::Eternal).
Definition HolderTraits.h:20
Traits template that lets the library hold objects through custom smart pointers.
Definition HolderTraits.h:156

Built-In Holders

The library provides built-in traits for standard and library smart pointers. Built-in owning holders declare a HolderKind:

Holder Kind
RefPtr Shared
std::shared_ptr Shared
std::unique_ptr Exclusive
js::Eternal Shared

The holder's kind determines how the library manages your object's lifetime:

  • Shared holders share ownership between native code and the library. Copies keep the object alive until native code and any JavaScript wrapper, DOM listener, or data binding release it.
  • Exclusive holders transfer unique ownership to the library. Moving the pointer leaves your native holder empty, and the library keeps the object alive for as long as the wrapper, DOM listener, or data binding exists.

WeakPtr and std::weak_ptr serve as built-in weak holders by defining Lock() instead of a kind. A weak holder doesn't keep your object alive– the library temporarily locks it for each call, skipping the operation if the object has been destroyed, or throwing an error when called from JavaScript.

Custom Smart Pointers

A single specialization works across the JavaScript, DOM, and data-binding APIs. Specialize the template as an owning holder or a weak holder, depending on how your pointer manages lifetime:

  • An owning holder defines element_type, kind, and Get(). Set kind to HolderKind::Shared or HolderKind::Exclusive, and return a raw pointer from Get().
  • A weak holder defines element_type and Lock(). Return an owning holder from Lock() to provide temporary access to the instance during a call.

This example specializes HolderTraits for an engine weak pointer:

template <typename T>
struct ultralight::HolderTraits<MyWeakRef<T>> {
using element_type = T;
static MyRef<T> Lock(const MyWeakRef<T>& holder) { return holder.lock(); }
};
constexpr Lock()=default

To use your custom owning holder as the canonical holder for a bound class, specialize js::ClassHolder for that class.

Custom specializations take priority over built-in traits.

Warning
Declare your specialization in namespace ultralight before any code passes the pointer to the library. If the compiler encounters code using the holder before seeing your specialization, it either falls back silently to built-in traits or fails to build.
See also
js::ClassHolder, js::Bind(), dom::LockableHolder, js::Eternal
Inheritance diagram for HolderTraits< H, typename >:

The documentation for this struct was generated from the following file: