init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s

This commit is contained in:
allhaileris
2026-02-16 15:50:16 +03:00
commit afb81b8278
13816 changed files with 3689732 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#include "tl/tl_basic_types.h"
namespace tl {
QString utf16(const QByteArray &v) {
return QString::fromUtf8(v);
}
} // namespace tl

View File

@@ -0,0 +1,683 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#pragma once
#include "base/basic_types.h"
#include "base/flags.h"
#include "base/bytes.h"
#include <QtCore/QVector>
namespace tl {
namespace details {
struct zero_flags_helper {
};
struct LengthCounter {
uint32 length = 0;
};
} // namespace details
template <typename Accumulator>
struct Writer;
template <typename Prime>
struct Reader;
template <>
struct Writer<details::LengthCounter> final {
static void PutBytes(details::LengthCounter &to, const void *bytes, uint32 count) noexcept {
constexpr auto kPrime = sizeof(uint32);
const auto primes = (count / kPrime) + (count % kPrime ? 1 : 0);
to.length += primes * kPrime;
}
static void Put(details::LengthCounter &to, uint32 value) noexcept {
to.length += sizeof(uint32);
}
};
template <
typename T,
typename = decltype(
std::declval<T>().write(std::declval<details::LengthCounter&>()))>
uint32 count_length(const T &value) noexcept {
auto counter = details::LengthCounter();
value.write(counter);
return counter.length;
}
enum {
id_int = 0xa8509bda,
id_long = 0x22076cba,
id_int128 = 0x4bb5362b,
id_int256 = 0x929c32f,
id_double = 0x2210c154,
id_string = 0xb5286e24,
id_vector = 0x1cb5c415,
id_bytes = id_string,
id_flags = id_int,
id_flags64 = id_long,
};
class int_type {
public:
int32 v = 0;
constexpr int_type() noexcept = default;
constexpr uint32 type() const noexcept {
return id_int;
}
template <typename Prime>
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_int) noexcept {
if (!Reader<Prime>::Has(1, from, end) || cons != id_int) {
return false;
}
v = static_cast<int32>(Reader<Prime>::Get(from, end));
return true;
}
template <typename Accumulator>
void write(Accumulator &to) const noexcept {
Writer<Accumulator>::Put(to, static_cast<uint32>(v));
}
private:
explicit constexpr int_type(int32 val) noexcept : v(val) {
}
friend constexpr int_type make_int(int32 v) noexcept;
};
inline constexpr int_type make_int(int32 v) noexcept {
return int_type(v);
}
template <typename Flags>
class flags_type {
public:
Flags v = 0;
static_assert(
sizeof(Flags) == sizeof(int32) || sizeof(Flags) == sizeof(int64),
"flags_type are allowed only wrapping int32 or int64 flag types!");
constexpr flags_type() noexcept = default;
constexpr flags_type(details::zero_flags_helper helper) noexcept {
}
constexpr uint32 type() const noexcept {
return (sizeof(Flags) == sizeof(int32)) ? id_flags : id_flags64;
}
template <typename Prime>
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_flags) noexcept {
if (!Reader<Prime>::Has(1, from, end) || cons != id_flags) {
return false;
}
v = Flags::from_raw(static_cast<typename Flags::Type>(Reader<Prime>::Get(from, end)));
if constexpr (sizeof(Flags) != sizeof(int32)) {
if (!Reader<Prime>::Has(1, from, end)) {
return false;
}
v |= Flags::from_raw(static_cast<typename Flags::Type>(Reader<Prime>::Get(from, end)) << 32);
}
return true;
}
template <typename Accumulator>
void write(Accumulator &to) const noexcept {
if constexpr (sizeof(Flags) == sizeof(int32)) {
Writer<Accumulator>::Put(to, static_cast<uint32>(v.value()));
} else {
Writer<Accumulator>::Put(to, static_cast<uint32>(v.value() & 0xFFFFFFFFULL));
Writer<Accumulator>::Put(to, static_cast<uint32>(v.value() >> 32));
}
}
private:
explicit constexpr flags_type(Flags val) noexcept : v(val) {
}
template <typename T>
friend constexpr flags_type<base::flags<T>> make_flags(base::flags<T> v) noexcept;
template <typename T, typename>
friend constexpr flags_type<base::flags<T>> make_flags(T v) noexcept;
};
template <typename T>
inline constexpr flags_type<base::flags<T>> make_flags(base::flags<T> v) noexcept {
return flags_type<base::flags<T>>(v);
}
template <typename T, typename = std::enable_if_t<!std::is_same<T, int>::value>>
inline constexpr flags_type<base::flags<T>> make_flags(T v) noexcept {
return flags_type<base::flags<T>>(v);
}
inline constexpr details::zero_flags_helper make_flags(void(details::zero_flags_helper::*)()) noexcept {
return details::zero_flags_helper();
}
inline constexpr bool operator==(const int_type &a, const int_type &b) noexcept {
return a.v == b.v;
}
inline constexpr bool operator!=(const int_type &a, const int_type &b) noexcept {
return a.v != b.v;
}
class long_type {
public:
uint64 v = 0;
constexpr long_type() noexcept = default;
constexpr uint32 type() const noexcept {
return id_long;
}
template <typename Prime>
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_long) noexcept {
if (!Reader<Prime>::Has(2, from, end) || cons != id_long) {
return false;
}
v = static_cast<uint64>(Reader<Prime>::Get(from, end));
v |= static_cast<uint64>(Reader<Prime>::Get(from, end)) << 32;
return true;
}
template <typename Accumulator>
void write(Accumulator &to) const noexcept {
Writer<Accumulator>::Put(to, static_cast<uint32>(v & 0xFFFFFFFFULL));
Writer<Accumulator>::Put(to, static_cast<uint32>(v >> 32));
}
private:
explicit constexpr long_type(uint64 val) noexcept : v(val) {
}
friend constexpr long_type make_long(uint64 v) noexcept;
};
inline constexpr long_type make_long(uint64 v) noexcept {
return long_type(v);
}
inline constexpr bool operator==(const long_type &a, const long_type &b) noexcept {
return a.v == b.v;
}
inline constexpr bool operator!=(const long_type &a, const long_type &b) noexcept {
return a.v != b.v;
}
class int64_type {
public:
int64 v = 0;
constexpr int64_type() noexcept = default;
constexpr uint32 type() const noexcept {
return id_long;
}
template <typename Prime>
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_long) noexcept {
if (!Reader<Prime>::Has(2, from, end) || cons != id_long) {
return false;
}
auto data = static_cast<uint64>(Reader<Prime>::Get(from, end));
data |= static_cast<uint64>(Reader<Prime>::Get(from, end)) << 32;
v = static_cast<int64>(data);
return true;
}
template <typename Accumulator>
void write(Accumulator &to) const noexcept {
const auto data = static_cast<uint64>(v);
Writer<Accumulator>::Put(to, static_cast<uint32>(data & 0xFFFFFFFFULL));
Writer<Accumulator>::Put(to, static_cast<uint32>(data >> 32));
}
private:
explicit constexpr int64_type(int64 val) noexcept : v(val) {
}
friend constexpr int64_type make_int64(int64 v) noexcept;
};
inline constexpr int64_type make_int64(int64 v) noexcept {
return int64_type(v);
}
inline constexpr bool operator==(const int64_type &a, const int64_type &b) noexcept {
return a.v == b.v;
}
inline constexpr bool operator!=(const int64_type &a, const int64_type &b) noexcept {
return a.v != b.v;
}
class int128_type {
public:
uint64 l = 0;
uint64 h = 0;
constexpr int128_type() noexcept = default;
constexpr uint32 type() const noexcept {
return id_int128;
}
template <typename Prime>
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_int128) noexcept {
if (!Reader<Prime>::Has(4, from, end) || cons != id_int128) {
return false;
}
l = static_cast<uint64>(Reader<Prime>::Get(from, end));
l |= static_cast<uint64>(Reader<Prime>::Get(from, end)) << 32;
h = static_cast<uint64>(Reader<Prime>::Get(from, end));
h |= static_cast<uint64>(Reader<Prime>::Get(from, end)) << 32;
return true;
}
template <typename Accumulator>
void write(Accumulator &to) const noexcept {
Writer<Accumulator>::Put(to, static_cast<uint32>(l & 0xFFFFFFFFULL));
Writer<Accumulator>::Put(to, static_cast<uint32>(l >> 32));
Writer<Accumulator>::Put(to, static_cast<uint32>(h & 0xFFFFFFFFULL));
Writer<Accumulator>::Put(to, static_cast<uint32>(h >> 32));
}
private:
explicit constexpr int128_type(uint64 low, uint64 high) noexcept : l(low), h(high) {
}
friend constexpr int128_type make_int128(uint64 l, uint64 h) noexcept;
};
inline constexpr int128_type make_int128(uint64 l, uint64 h) noexcept {
return int128_type(l, h);
}
inline constexpr bool operator==(const int128_type &a, const int128_type &b) noexcept {
return a.l == b.l && a.h == b.h;
}
inline constexpr bool operator!=(const int128_type &a, const int128_type &b) noexcept {
return a.l != b.l || a.h != b.h;
}
class int256_type {
public:
int128_type l;
int128_type h;
constexpr int256_type() noexcept = default;
constexpr uint32 type() const noexcept {
return id_int256;
}
template <typename Prime>
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_int256) noexcept {
if (cons != id_int256) {
return false;
}
return l.read(from, end) && h.read(from, end);
}
template <typename Accumulator>
void write(Accumulator &to) const noexcept {
l.write(to);
h.write(to);
}
private:
explicit constexpr int256_type(int128_type low, int128_type high) noexcept : l(low), h(high) {
}
friend constexpr int256_type make_int256(const int128_type &l, const int128_type &h) noexcept;
};
inline constexpr int256_type make_int256(const int128_type &l, const int128_type &h) noexcept {
return int256_type(l, h);
}
inline constexpr bool operator==(const int256_type &a, const int256_type &b) noexcept {
return a.l == b.l && a.h == b.h;
}
inline constexpr bool operator!=(const int256_type &a, const int256_type &b) noexcept {
return a.l != b.l || a.h != b.h;
}
class double_type {
public:
float64 v = 0.;
constexpr double_type() noexcept = default;
constexpr uint32 type() const noexcept {
return id_double;
}
template <typename Prime>
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_double) noexcept {
if (!Reader<Prime>::Has(2, from, end) || cons != id_double) {
return false;
}
auto nonaliased = static_cast<uint64>(Reader<Prime>::Get(from, end));
nonaliased |= static_cast<uint64>(Reader<Prime>::Get(from, end)) << 32;
static_assert(sizeof(v) == sizeof(nonaliased));
std::memcpy(&v, &nonaliased, sizeof(v));
return true;
}
template <typename Accumulator>
void write(Accumulator &to) const noexcept {
auto nonaliased = uint64();
static_assert(sizeof(v) == sizeof(nonaliased));
std::memcpy(&nonaliased, &v, sizeof(v));
Writer<Accumulator>::Put(to, static_cast<uint32>(nonaliased & 0xFFFFFFFFULL));
Writer<Accumulator>::Put(to, static_cast<uint32>(nonaliased >> 32));
}
private:
explicit constexpr double_type(float64 val) noexcept : v(val) {
}
friend constexpr double_type make_double(float64 v) noexcept;
};
inline constexpr double_type make_double(float64 v) noexcept {
return double_type(v);
}
inline constexpr bool operator==(const double_type &a, const double_type &b) noexcept {
return a.v == b.v;
}
inline constexpr bool operator!=(const double_type &a, const double_type &b) noexcept {
return a.v != b.v;
}
class string_type;
using bytes_type = string_type;
class string_type {
public:
string_type() noexcept = default;
uint32 type() const noexcept {
return id_string;
}
template <typename Prime>
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_string) noexcept {
if (!Reader<Prime>::Has(1, from, end) || cons != id_string) {
return false;
}
const auto first = Reader<Prime>::Get(from, end);
const auto last = (first & 0xFFU);
if (last > 254) {
return false;
} else if (last == 0) {
v = QByteArray();
} else if (last == 1) {
v = QByteArray(1, static_cast<char>((first >> 8) & 0xFFU));
} else if (last == 2) {
v = QByteArray(2, Qt::Uninitialized);
v[0] = static_cast<char>((first >> 8) & 0xFFU);
v[1] = static_cast<char>((first >> 16) & 0xFFU);
} else if (last < 254) {
v = QByteArray(last, Qt::Uninitialized);
const auto remaining = last - 3;
if (!Reader<Prime>::HasBytes(remaining, from, end)) {
return false;
}
v[0] = static_cast<char>((first >> 8) & 0xFFU);
v[1] = static_cast<char>((first >> 16) & 0xFFU);
v[2] = static_cast<char>((first >> 24) & 0xFFU);
Reader<Prime>::GetBytes(v.data() + 3, remaining, from, end);
} else {
const auto length = (first >> 8);
if (!Reader<Prime>::HasBytes(length, from, end)) {
return false;
}
v = QByteArray(length, Qt::Uninitialized);
Reader<Prime>::GetBytes(v.data(), length, from, end);
}
return true;
}
template <typename Accumulator>
void write(Accumulator &to) const noexcept {
Expects(v.size() < 0x1000000);
const auto size = uint32(v.size());
if (size == 0) {
Writer<Accumulator>::Put(to, size);
} else if (size == 1) {
Writer<Accumulator>::Put(to, size
| (static_cast<uint32>(static_cast<uchar>(v[0])) << 8));
} else if (size == 2) {
Writer<Accumulator>::Put(to, size
| (static_cast<uint32>(static_cast<uchar>(v[0])) << 8)
| (static_cast<uint32>(static_cast<uchar>(v[1])) << 16));
} else if (size < 254) {
Writer<Accumulator>::Put(to, size
| (static_cast<uint32>(static_cast<uchar>(v[0])) << 8)
| (static_cast<uint32>(static_cast<uchar>(v[1])) << 16)
| (static_cast<uint32>(static_cast<uchar>(v[2])) << 24));
Writer<Accumulator>::PutBytes(to, v.data() + 3, size - 3);
} else {
const auto encoded = (size << 8) | 254U;
Writer<Accumulator>::Put(to, encoded);
Writer<Accumulator>::PutBytes(to, v.data(), size);
}
}
QByteArray v;
private:
explicit string_type(QByteArray &&data) noexcept : v(std::move(data)) {
}
friend string_type make_string(const std::string &v);
friend string_type make_string(const QByteArray &v);
friend string_type make_string(QByteArray &&v);
friend string_type make_string(const QString &v);
friend string_type make_string(const char *v);
friend string_type make_string();
friend bytes_type make_bytes(const QByteArray &v);
friend bytes_type make_bytes(QByteArray &&v);
friend bytes_type make_bytes();
};
inline string_type make_string(const std::string &v) {
return string_type(QByteArray(v.data(), v.size()));
}
inline string_type make_string(const QByteArray &v) {
return string_type(QByteArray(v));
}
inline string_type make_string(QByteArray &&v) {
return string_type(std::move(v));
}
inline string_type make_string(const QString &v) {
return string_type(v.toUtf8());
}
inline string_type make_string(const char *v) {
return string_type(QByteArray(v, strlen(v)));
}
inline string_type make_string() {
return string_type(QByteArray());
}
inline bytes_type make_bytes(const QByteArray &v) {
return bytes_type(QByteArray(v));
}
inline bytes_type make_bytes(QByteArray &&v) {
return bytes_type(std::move(v));
}
inline bytes_type make_bytes() {
return bytes_type(QByteArray());
}
inline bytes_type make_bytes(bytes::const_span buffer) {
return make_bytes(QByteArray(
reinterpret_cast<const char*>(buffer.data()),
buffer.size()));
}
inline bytes_type make_bytes(const bytes::vector &buffer) {
return make_bytes(bytes::make_span(buffer));
}
inline bool operator==(const string_type &a, const string_type &b) {
return a.v == b.v;
}
inline bool operator!=(const string_type &a, const string_type &b) {
return a.v != b.v;
}
QString utf16(const QByteArray &v);
inline QByteArray utf8(const QByteArray &v) {
return v;
}
inline QString utf16(const string_type &v) {
return utf16(v.v);
}
inline QByteArray utf8(const string_type &v) {
return utf8(v.v);
}
template <typename T>
class vector_type {
public:
vector_type() noexcept = default;
uint32 type() const noexcept {
return id_vector;
}
template <typename Prime>
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = id_vector) noexcept {
if (!Reader<Prime>::Has(1, from, end) || cons != id_vector) {
return false;
}
auto count = Reader<Prime>::Get(from, end);
auto vector = QVector<T>(count, T());
for (auto &item : vector) {
if (!item.read(from, end)) {
return false;
}
}
v = std::move(vector);
return true;
}
template <typename Accumulator>
void write(Accumulator &to) const noexcept {
Writer<Accumulator>::Put(to, static_cast<int32>(v.size()));
for (const auto &item : v) {
item.write(to);
}
}
QVector<T> v;
private:
explicit vector_type(QVector<T> &&data) noexcept : v(std::move(data)) {
}
template <typename U>
friend vector_type<U> make_vector(uint32 count);
template <typename U>
friend vector_type<U> make_vector(uint32 count, const U &value);
template <typename U>
friend vector_type<U> make_vector(const QVector<U> &v);
template <typename U>
friend vector_type<U> make_vector(QVector<U> &&v);
template <typename U>
friend vector_type<U> make_vector();
};
template <typename T>
inline vector_type<T> make_vector(uint32 count) {
return vector_type<T>(QVector<T>(count));
}
template <typename T>
inline vector_type<T> make_vector(uint32 count, const T &value) {
return vector_type<T>(QVector<T>(count, value));
}
template <typename T>
inline vector_type<T> make_vector(const QVector<T> &v) {
return vector_type<T>(QVector<T>(v));
}
template <typename T>
inline vector_type<T> make_vector(QVector<T> &&v) {
return vector_type<T>(std::move(v));
}
template <typename T>
inline vector_type<T> make_vector() {
return vector_type<T>();
}
template <typename T>
inline bool operator==(const vector_type<T> &a, const vector_type<T> &b) {
return a.c_vector().v == b.c_vector().v;
}
template <typename T>
inline bool operator!=(const vector_type<T> &a, const vector_type<T> &b) {
return a.c_vector().v != b.c_vector().v;
}
namespace details {
template <typename Type>
struct repeat_helper {
using type = Type;
};
template <typename Type>
using repeat = typename repeat_helper<Type>::type;
struct inner_helper {
static void Check(...);
template <typename Type, typename Result = decltype(std::declval<Type>().v)>
static Result Check(const Type&);
template <typename Type>
using type = std::decay_t<decltype(Check(std::declval<Type>()))>;
};
} // namespace details
template <typename T>
class conditional {
public:
constexpr conditional() noexcept = default;
constexpr conditional(const T *value) noexcept : _value(value) {
}
constexpr operator const T*() const noexcept {
return _value;
}
constexpr const T *operator->() const noexcept {
Expects(_value != nullptr);
return _value;
}
constexpr const T &operator*() const noexcept {
Expects(_value != nullptr);
return *_value;
}
template <
typename Inner = details::inner_helper::type<T>,
typename = std::enable_if_t<!std::is_same_v<Inner, void>>>
constexpr Inner value_or(details::repeat<Inner> fallback) const noexcept {
return _value ? _value->v : fallback;
}
template <
typename Inner = details::inner_helper::type<T>,
typename = std::enable_if_t<!std::is_same_v<Inner, void>>>
constexpr Inner value_or_empty() const noexcept {
return _value ? _value->v : Inner();
}
constexpr bool has_value() const noexcept {
return (_value != nullptr);
}
private:
const T *_value = nullptr;
};
} // namespace tl

View File

@@ -0,0 +1,67 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#pragma once
#include "base/basic_types.h"
#include <QtCore/QVector>
namespace tl {
template <typename Accumulator>
struct Writer;
template <typename bare>
class boxed : public bare {
public:
using bare::bare;
boxed() = default;
boxed(const boxed<bare> &v) = default;
boxed<bare> &operator=(const boxed<bare> &v) & = default;
boxed(const bare &v) : bare(v) {
}
boxed<bare> &operator=(const bare &v) & {
*((bare*)this) = v;
return *this;
}
template <typename Prime>
[[nodiscard]] bool read(const Prime *&from, const Prime *end, uint32 cons = 0) {
if (!Reader<Prime>::Has(1, from, end)) {
return false;
}
cons = Reader<Prime>::Get(from, end);
return bare::read(from, end, cons);
}
template <typename Accumulator>
void write(Accumulator &to) const {
Writer<Accumulator>::Put(to, bare::type());
bare::write(to);
}
using Unboxed = bare;
};
template <typename T>
class boxed<boxed<T> > {
using Unboxed = typename T::CantMakeBoxedBoxedType;
};
template <typename T>
struct is_boxed : std::false_type {
};
template <typename T>
struct is_boxed<boxed<T>> : std::true_type {
};
template <typename T>
inline constexpr bool is_boxed_v = is_boxed<T>::value;
} // namespace tl

View File

@@ -0,0 +1,100 @@
// This file is part of Desktop App Toolkit,
// a set of libraries for developing nice desktop applications.
//
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#pragma once
#include "base/algorithm.h"
namespace tl::details {
class type_data {
public:
type_data() = default;
type_data(const type_data &other) = delete;
type_data(type_data &&other) = delete;
type_data &operator=(const type_data &other) = delete;
type_data &operator=(type_data &&other) = delete;
virtual ~type_data() {
}
private:
void incrementCounter() const {
_counter.ref();
}
bool decrementCounter() const {
return _counter.deref();
}
friend class type_owner;
mutable QAtomicInt _counter = { 1 };
};
class type_owner {
public:
type_owner(type_owner &&other) : _data(base::take(other._data)) {
}
type_owner(const type_owner &other) : _data(other._data) {
incrementCounter();
}
type_owner &operator=(type_owner &&other) {
if (other._data != _data) {
decrementCounter();
_data = base::take(other._data);
}
return *this;
}
type_owner &operator=(const type_owner &other) {
if (other._data != _data) {
setData(other._data);
incrementCounter();
}
return *this;
}
~type_owner() {
decrementCounter();
}
protected:
type_owner() = default;
type_owner(const type_data *data) : _data(data) {
}
void setData(const type_data *data) {
decrementCounter();
_data = data;
}
// Unsafe cast, type should be checked by the caller.
template <typename DataType>
const DataType &queryData() const {
Expects(_data != nullptr);
return static_cast<const DataType &>(*_data);
}
bool hasData() const {
return _data != nullptr;
}
private:
void incrementCounter() {
if (_data) {
_data->incrementCounter();
}
}
void decrementCounter() {
if (_data && !_data->decrementCounter()) {
delete base::take(_data);
}
}
const type_data *_data = nullptr;
};
} // namespace tl::details