major: initial release

* initial development

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* pipeline

* ci/cd

* ci/cd

* ci/cd

* ci/cd

* ci/cd

* ci/cd

* ci/cd

* pokemon

* pokemon

* pokemon

* pokemon

* pokemon

* pokemon

* improvements

* improvements

* ci/cd

* ci/cd

* improvements

* improvements

* improvements

* improvements

* improvements

* improvements

* improvements

* improvements

* improvements

---------

Co-authored-by: sdine <sdine@sdine.com>
This commit is contained in:
Sebastian Dine
2026-05-09 11:05:47 +02:00
committed by GitHub
parent 13262fa015
commit 55ace147bc
149 changed files with 12611 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
#pragma once
// Pure functions for filename munging. Ported from the original `util/fs.rs` so
// that file naming on disk stays identical between the two codebases.
#include <cstdint>
#include <string>
#include <string_view>
namespace ccm {
// Replace problematic characters so the result is safe to use as a filename
// component. Mirrors `format_text_for_fs` in Rust (drops apostrophes/commas,
// strips spaces, replaces `:` with `-`, `&` with `And`, `|` with `Or`,
// flattens accented vowels). Pure; safe at any call site.
std::string formatTextForFs(std::string_view text);
// Parse the trailing 1- or 2-digit numeric index from a filename. Examples:
// "Image1.png" -> 1
// "Image22.jpeg" -> 22
// Returns 0 on parse failure, matching the optimistic Rust behavior.
std::uint8_t parseIndexFromFilename(std::string_view filename) noexcept;
} // namespace ccm
+150
View File
@@ -0,0 +1,150 @@
#pragma once
// A minimal Result<T, E> type used as a sum-type for fallible operations.
// Mirrors the Rust `Result<T, &str>` style used in the original codebase.
//
// We intentionally do not depend on tl::expected or std::expected so this
// header stays buildable on every toolchain in our matrix (clang 14+, GCC 11+).
#include <new>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
namespace ccm {
template <typename T, typename E = std::string>
class Result {
public:
using value_type = T;
using error_type = E;
static Result ok(T value) { return Result(OkTag{}, std::move(value)); }
static Result err(E error) { return Result(ErrTag{}, std::move(error)); }
Result(const Result& other) : has_value_(other.has_value_) {
if (has_value_) {
::new (static_cast<void*>(&value_)) T(other.value_);
} else {
::new (static_cast<void*>(&error_)) E(other.error_);
}
}
Result(Result&& other) noexcept : has_value_(other.has_value_) {
if (has_value_) {
::new (static_cast<void*>(&value_)) T(std::move(other.value_));
} else {
::new (static_cast<void*>(&error_)) E(std::move(other.error_));
}
}
Result& operator=(const Result& other) {
if (this == &other) return *this;
destroy();
has_value_ = other.has_value_;
if (has_value_) {
::new (static_cast<void*>(&value_)) T(other.value_);
} else {
::new (static_cast<void*>(&error_)) E(other.error_);
}
return *this;
}
Result& operator=(Result&& other) noexcept {
if (this == &other) return *this;
destroy();
has_value_ = other.has_value_;
if (has_value_) {
::new (static_cast<void*>(&value_)) T(std::move(other.value_));
} else {
::new (static_cast<void*>(&error_)) E(std::move(other.error_));
}
return *this;
}
~Result() { destroy(); }
[[nodiscard]] bool isOk() const noexcept { return has_value_; }
[[nodiscard]] bool isErr() const noexcept { return !has_value_; }
explicit operator bool() const noexcept { return has_value_; }
const T& value() const& {
if (!has_value_) throw std::logic_error("Result::value() on err");
return value_;
}
T& value() & {
if (!has_value_) throw std::logic_error("Result::value() on err");
return value_;
}
T&& value() && {
if (!has_value_) throw std::logic_error("Result::value() on err");
return std::move(value_);
}
const E& error() const& {
if (has_value_) throw std::logic_error("Result::error() on ok");
return error_;
}
E&& error() && {
if (has_value_) throw std::logic_error("Result::error() on ok");
return std::move(error_);
}
template <typename U>
T valueOr(U&& fallback) const& {
return has_value_ ? value_ : static_cast<T>(std::forward<U>(fallback));
}
private:
struct OkTag {};
struct ErrTag {};
Result(OkTag, T value) : has_value_(true) {
::new (static_cast<void*>(&value_)) T(std::move(value));
}
Result(ErrTag, E error) : has_value_(false) {
::new (static_cast<void*>(&error_)) E(std::move(error));
}
void destroy() noexcept {
if (has_value_) {
value_.~T();
} else {
error_.~E();
}
}
bool has_value_;
union {
T value_;
E error_;
};
};
// Specialization for void-returning fallible operations.
template <typename E>
class Result<void, E> {
public:
using value_type = void;
using error_type = E;
static Result ok() { return Result(true, E{}); }
static Result err(E error) { return Result(false, std::move(error)); }
[[nodiscard]] bool isOk() const noexcept { return has_value_; }
[[nodiscard]] bool isErr() const noexcept { return !has_value_; }
explicit operator bool() const noexcept { return has_value_; }
const E& error() const& {
if (has_value_) throw std::logic_error("Result::error() on ok");
return error_;
}
private:
Result(bool ok, E error) : has_value_(ok), error_(std::move(error)) {}
bool has_value_;
E error_;
};
} // namespace ccm