Skip to content

Instantly share code, notes, and snippets.

@X547
Created November 12, 2025 23:38
Show Gist options
  • Select an option

  • Save X547/2d0bf5aaa944137c300457113767374c to your computer and use it in GitHub Desktop.

Select an option

Save X547/2d0bf5aaa944137c300457113767374c to your computer and use it in GitHub Desktop.
C++ traits with stable ABI
#pragma once
#include <stddef.h>
#include <stdint.h>
template <class T, class M>
static inline constexpr ptrdiff_t OffsetOf(const M T::*member)
{
return reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<T*>(0)->*member));
}
template <class T, class M>
static inline constexpr T& ContainerOf(M &ptr, const M T::*member)
{
return *reinterpret_cast<T*>(reinterpret_cast<intptr_t>(&ptr) - OffsetOf(member));
}
template <class T, class M>
static inline constexpr T& ContainerOf(const M &ptr, const M T::*member)
{
return *reinterpret_cast<T*>(reinterpret_cast<intptr_t>(&ptr) - OffsetOf(member));
}
#pragma once
#include <drivers/Drivers.h>
#include "ContainerOf.h"
#include "DeviceRoster.h"
class DevfsNodeHandle;
class DevfsNode {
public:
const device_hooks* fCls;
public:
DevfsNode(const device_hooks* cls = nullptr): fCls(cls) {}
status_t Open(const char *path, uint32 flags, DevfsNodeHandle& handle);
};
class DevfsNodeHandle {
public:
const device_hooks* fCls;
void* fInst;
public:
DevfsNodeHandle(const device_hooks* cls = nullptr, void* inst = nullptr): fCls(cls), fInst(inst) {}
status_t Close();
status_t Free();
struct Read {
operator bool();
status_t operator()(off_t pos, void *buffer, size_t *_length);
} Read;
struct Write {
operator bool();
status_t operator()(off_t pos, const void *buffer, size_t *_length);
} Write;
struct Control {
operator bool();
status_t operator()(uint32 op, void *buffer, size_t length);
} Control;
struct Select {
operator bool();
status_t operator()(uint8 event, uint32 ref, selectsync *sync);
} Select;
struct Deselect {
operator bool();
status_t operator()(uint8 event, selectsync *sync);
} Deselect;
};
// #pragma mark -
template <typename DevfsNodeImpl, typename DevfsNodeHandleImpl>
constexpr device_hooks_ex GetDevfsNodeClass()
{
device_hooks_ex cls {};
cls.open = [](const char *name, uint32 flags, void **cookie) {
int32 idx = FindDevfsNode(name);
if (idx < 0)
return ENOENT;
DevfsNodeHandle handle;
status_t res = static_cast<DevfsNodeImpl*>(gDevfsNodeInsts[idx])->Open(flags, handle);
*cookie = handle.fInst;
return res;
};
cls.close = [](void *cookie) {
return static_cast<DevfsNodeHandleImpl*>(cookie)->Close();
};
cls.free = [](void *cookie) {
delete static_cast<DevfsNodeHandleImpl*>(cookie);
return B_OK;
};
if constexpr (requires(DevfsNodeHandleImpl h, off_t pos, void *buffer, size_t *_length) {
h.Read(pos, buffer, _length);
}) {
cls.read = [](void *cookie, off_t pos, void *buffer, size_t *_length) {
return static_cast<DevfsNodeHandleImpl*>(cookie)->Read(pos, buffer, _length);
};
}
if constexpr (requires(DevfsNodeHandleImpl h, off_t pos, const void *buffer, size_t *_length) {
h.Write(pos, buffer, _length);
}) {
cls.write = [](void *cookie, off_t pos, const void *buffer, size_t *_length) {
return static_cast<DevfsNodeHandleImpl*>(cookie)->Write(pos, buffer, _length);
};
}
if constexpr (requires(DevfsNodeHandleImpl h, uint32 op, void *buffer, size_t length) {
h.Control(op, buffer, length);
}) {
cls.control = [](void *cookie, uint32 op, void *buffer, size_t length) {
return static_cast<DevfsNodeHandleImpl*>(cookie)->Control(op, buffer, length);
};
}
if constexpr (requires(DevfsNodeHandleImpl h, uint8 event, uint32 ref, selectsync *sync) {
h.Select(event, ref, sync);
}) {
cls.select = [](void *cookie, uint8 event, uint32 ref, selectsync *sync) {
return static_cast<DevfsNodeHandleImpl*>(cookie)->Select(event, ref, sync);
};
}
if constexpr (requires(DevfsNodeHandleImpl h, uint8 event, selectsync *sync) {
h.Deselect(event, sync);
}) {
cls.deselect = [](void *cookie, uint8 event, selectsync *sync) {
return static_cast<DevfsNodeHandleImpl*>(cookie)->Deselect(event, sync);
};
}
cls.free_device = [](void *cookie) {
delete static_cast<DevfsNodeImpl*>(cookie);
};
return cls;
}
// #pragma mark - DevfsNode
inline status_t DevfsNode::Open(const char *path, uint32 flags, DevfsNodeHandle& handle)
{
handle.fCls = fCls;
return fCls->open(path, flags, &handle.fInst);
}
// #pragma mark - DevfsNodeHandle
inline status_t DevfsNodeHandle::Close()
{
return fCls->close(fInst);
}
inline status_t DevfsNodeHandle::Free()
{
status_t res = fCls->free(fInst);
fInst = nullptr;
return res;
}
inline DevfsNodeHandle::Read::operator bool()
{
DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Read);
return base.fCls->read != nullptr;
}
inline status_t DevfsNodeHandle::Read::operator()(off_t pos, void *buffer, size_t *_length)
{
DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Read);
return base.fCls->read(base.fInst, pos, buffer, _length);
}
inline DevfsNodeHandle::Write::operator bool()
{
DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Write);
return base.fCls->write != nullptr;
}
inline status_t DevfsNodeHandle::Write::operator()(off_t pos, const void *buffer, size_t *_length)
{
DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Write);
return base.fCls->write(base.fInst, pos, buffer, _length);
}
inline DevfsNodeHandle::Control::operator bool()
{
DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Control);
return base.fCls->control != nullptr;
}
inline status_t DevfsNodeHandle::Control::operator()(uint32 op, void *buffer, size_t length)
{
DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Control);
return base.fCls->control(base.fInst, op, buffer, length);
}
inline DevfsNodeHandle::Select::operator bool()
{
DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Select);
return base.fCls->select != nullptr;
}
inline status_t DevfsNodeHandle::Select::operator()(uint8 event, uint32 ref, selectsync *sync)
{
DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Select);
return base.fCls->select(base.fInst, event, ref, sync);
}
inline DevfsNodeHandle::Deselect::operator bool()
{
DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Deselect);
return base.fCls->deselect != nullptr;
}
inline status_t DevfsNodeHandle::Deselect::operator()(uint8 event, selectsync *sync)
{
DevfsNodeHandle& base = ContainerOf(*this, &DevfsNodeHandle::Deselect);
return base.fCls->deselect(base.fInst, event, sync);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment