master ohmu/fastfetch-openbsd / src / common / windows / variant.hpp
ohmu  ·  2026-10-15
  1#include <oaidl.h>
  2#include <propidl.h>
  3#include <type_traits>
  4#include <utility>
  5#include <string_view>
  6#include <cassert>
  7#include <cstdint>
  8
  9template <typename TVariant>
 10struct FFBaseVariant : TVariant {
 11    bool hasValue() {
 12        return this->vt != VT_EMPTY;
 13    }
 14
 15    explicit operator bool() {
 16        return this->hasValue();
 17    }
 18
 19    template <typename T>
 20    T get() {
 21        // boolean
 22        if constexpr (std::is_same_v<T, bool>) {
 23            assert(this->vt == VT_BOOL);
 24            return this->boolVal != VARIANT_FALSE;
 25        }
 26
 27        // signed
 28        else if constexpr (std::is_same_v<T, int8_t>) {
 29            assert(this->vt == VT_I1);
 30            return this->cVal;
 31        } else if constexpr (std::is_same_v<T, int16_t>) {
 32            assert(this->vt == VT_I2);
 33            return this->iVal;
 34        } else if constexpr (std::is_same_v<T, int32_t>) {
 35            assert(this->vt == VT_I4 || this->vt == VT_INT);
 36            return this->intVal;
 37        } else if constexpr (std::is_same_v<T, int64_t>) {
 38            assert(this->vt == VT_I8);
 39            return this->llVal;
 40        }
 41
 42        // unsigned
 43        else if constexpr (std::is_same_v<T, uint8_t>) {
 44            assert(this->vt == VT_UI1);
 45            return this->bVal;
 46        } else if constexpr (std::is_same_v<T, uint16_t>) {
 47            assert(this->vt == VT_UI2);
 48            return this->uiVal;
 49        } else if constexpr (std::is_same_v<T, uint32_t>) {
 50            assert(this->vt == VT_UI4 || this->vt == VT_UINT);
 51            return this->uintVal;
 52        } else if constexpr (std::is_same_v<T, uint64_t>) {
 53            assert(this->vt == VT_UI8);
 54            return this->ullVal;
 55        }
 56
 57        // decimal
 58        else if constexpr (std::is_same_v<T, float>) {
 59            assert(this->vt == VT_R4);
 60            return this->fltVal;
 61        } else if constexpr (std::is_same_v<T, double>) {
 62            assert(this->vt == VT_R8);
 63            return this->dblVal;
 64        }
 65
 66        // string
 67        else if constexpr (std::is_same_v<T, std::string_view>) {
 68            assert(this->vt == VT_LPSTR);
 69            return this->pcVal;
 70        } else if constexpr (std::is_same_v<T, std::wstring_view>) {
 71            assert(this->vt == VT_BSTR || this->vt == VT_LPWSTR);
 72            if (this->vt == VT_LPWSTR) {
 73                return this->bstrVal;
 74            } else {
 75                return { this->bstrVal, SysStringLen(this->bstrVal) };
 76            }
 77        }
 78
 79        // array signed
 80        else if constexpr (std::is_same_v<T, std::pair<const int8_t*, uint32_t>>) {
 81            assert(this->vt & VT_ARRAY);
 82            assert((this->vt & ~VT_ARRAY) == VT_I1);
 83            return std::make_pair((int8_t*) this->parray->pvData, this->parray->cDims);
 84        } else if constexpr (std::is_same_v<T, std::pair<const int16_t*, uint32_t>>) {
 85            assert(this->vt & VT_ARRAY);
 86            assert((this->vt & ~VT_ARRAY) == VT_I2);
 87            return std::make_pair((int16_t*) this->parray->pvData, this->parray->cDims);
 88        } else if constexpr (std::is_same_v<T, std::pair<const int32_t*, uint32_t>>) {
 89            assert(this->vt & VT_ARRAY);
 90            assert((this->vt & ~VT_ARRAY) == VT_I4);
 91            return std::make_pair((int32_t*) this->parray->pvData, this->parray->cDims);
 92        } else if constexpr (std::is_same_v<T, std::pair<const int64_t*, uint32_t>>) {
 93            assert(this->vt & VT_ARRAY);
 94            assert((this->vt & ~VT_ARRAY) == VT_I8);
 95            return std::make_pair((int64_t*) this->parray->pvData, this->parray->cDims);
 96        }
 97
 98        // array unsigned
 99        else if constexpr (std::is_same_v<T, std::pair<const uint8_t*, uint32_t>>) {
100            assert(this->vt & VT_ARRAY);
101            assert((this->vt & ~VT_ARRAY) == VT_UI1);
102            return std::make_pair((uint8_t*) this->parray->pvData, this->parray->cDims);
103        } else if constexpr (std::is_same_v<T, std::pair<const uint16_t*, uint32_t>>) {
104            assert(this->vt & VT_ARRAY);
105            assert((this->vt & ~VT_ARRAY) == VT_UI2);
106            return std::make_pair((uint16_t*) this->parray->pvData, this->parray->cDims);
107        } else if constexpr (std::is_same_v<T, std::pair<const uint32_t*, uint32_t>>) {
108            assert(this->vt & VT_ARRAY);
109            assert((this->vt & ~VT_ARRAY) == VT_UI4);
110            return std::make_pair((uint32_t*) this->parray->pvData, this->parray->cDims);
111        } else if constexpr (std::is_same_v<T, std::pair<const uint64_t*, uint32_t>>) {
112            assert(this->vt & VT_ARRAY);
113            assert((this->vt & ~VT_ARRAY) == VT_UI8);
114            return std::make_pair((uint64_t*) this->parray->pvData, this->parray->cDims);
115        } else {
116            assert(false && "unsupported type");
117            __builtin_unreachable();
118        }
119    }
120};
121
122struct FFWmiVariant : FFBaseVariant<VARIANT> {
123    FFWmiVariant(const FFWmiVariant&) = delete;
124    FFWmiVariant(FFWmiVariant&&); // don't define it to enforce NRVO optimization
125    explicit FFWmiVariant() {
126        VariantInit(this);
127    }
128    explicit FFWmiVariant(std::initializer_list<PCWSTR> strings);
129    ~FFWmiVariant() {
130        VariantClear(this);
131    }
132};
133static_assert(sizeof(FFWmiVariant) == sizeof(VARIANT), "");
134
135struct FFPropVariant : FFBaseVariant<PROPVARIANT> {
136    FFPropVariant(const FFPropVariant&) = delete;
137    FFPropVariant(FFPropVariant&&); // don't define it to enforce NRVO optimization
138    explicit FFPropVariant() {
139        PropVariantInit(this);
140    }
141    ~FFPropVariant() {
142        PropVariantClear(this);
143    }
144};
145static_assert(sizeof(FFPropVariant) == sizeof(PROPVARIANT), "");
146
147namespace {
148// Provide our bstr_t to avoid libstdc++ dependency
149struct bstr_t {
150    explicit bstr_t(const wchar_t* str) noexcept : _bstr(SysAllocString(str)) {}
151    ~bstr_t(void) noexcept {
152        SysFreeString(_bstr);
153    }
154    explicit operator const wchar_t*(void) const noexcept {
155        return _bstr;
156    }
157    operator BSTR(void) const noexcept {
158        return _bstr;
159    }
160
161  private:
162    BSTR _bstr;
163};
164} // namespace