Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions foreign/cpp/.bazelignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target
200 changes: 166 additions & 34 deletions foreign/cpp/include/iggy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,46 +26,128 @@

namespace iggy {

/// Exception raised by the C++ client when an operation fails.
class IggyException : public std::runtime_error {
public:
explicit IggyException(const char *message) : std::runtime_error(message) {}
explicit IggyException(const std::string &message) : std::runtime_error(message) {}
};

class CompressionAlgorithm final {
namespace detail {

/// Internal helper used by string-backed option types in this header.
template <typename Tag>
class StringTag {
protected:
explicit StringTag(std::string value) : value_(std::move(value)) {}

std::string_view value() const { return value_; }

private:
std::string value_;
};

} // namespace detail

/// Compression setting for `Client::create_topic(...)`.
///
/// Use this type to choose whether messages in a topic are stored as-is or compressed with gzip.
///
/// Internally, this value is passed across the Rust FFI as a string.
/// Values outside the supported set are rejected by the Rust client.
/// Some Rust-side aliases may also be accepted for compatibility.
class CompressionAlgorithm final : private detail::StringTag<CompressionAlgorithm> {
public:
/// Store messages without compression.
static CompressionAlgorithm none() { return CompressionAlgorithm("none"); }
/// Compress messages with gzip.
static CompressionAlgorithm gzip() { return CompressionAlgorithm("gzip"); }

std::string_view compression_algorithm_value() const { return algorithm_; }
std::string_view compression_algorithm_value() const { return value(); }

private:
explicit CompressionAlgorithm(std::string algorithm) : algorithm_(std::move(algorithm)) {}

std::string algorithm_;
explicit CompressionAlgorithm(std::string algorithm)
: detail::StringTag<CompressionAlgorithm>(std::move(algorithm)) {}
};

class Expiry final {
/// Compression setting for `Client::snapshot(...)`.
///
/// Use this type to choose how snapshot data is compressed in the generated archive.
///
/// Internally, this value is passed across the Rust FFI as a string.
/// Values outside the supported set are rejected by the Rust client.
/// Some Rust-side aliases may also be accepted for compatibility.
class SnapshotCompression final : private detail::StringTag<SnapshotCompression> {
public:
static Expiry server_default() { return Expiry("server_default", 0); }
static Expiry never_expire() { return Expiry("never_expire", std::numeric_limits<std::uint64_t>::max()); }
static Expiry duration(std::uint64_t micros) { return Expiry("duration", micros); }

std::string_view expiry_kind() const { return expiry_kind_; }
std::uint64_t expiry_value() const { return expiry_value_; }
/// Store snapshot files without compression.
static SnapshotCompression stored() { return SnapshotCompression("stored"); }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

factory enforces a fixed enumeration but the FFI signature accepts String, which is then re-parsed in RustSnapshotCompression::from_str (client.rs:549). either pass an enum tag across FFI or document the parse-trip contract.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a warning + documented what each of enum and its options do.

/// Use standard deflate compression.
static SnapshotCompression deflated() { return SnapshotCompression("deflated"); }
/// Use bzip2 for a higher compression ratio at the cost of slower processing.
static SnapshotCompression bzip2() { return SnapshotCompression("bzip2"); }
/// Use Zstandard for fast compression and decompression.
static SnapshotCompression zstd() { return SnapshotCompression("zstd"); }
/// Use LZMA for high compression, especially for larger files.
static SnapshotCompression lzma() { return SnapshotCompression("lzma"); }
/// Use XZ, which is similar to LZMA and often faster to decompress.
static SnapshotCompression xz() { return SnapshotCompression("xz"); }

std::string_view snapshot_compression_value() const { return value(); }

private:
explicit Expiry(std::string expiry_kind, std::uint64_t expiry_value)
: expiry_kind_(std::move(expiry_kind)), expiry_value_(expiry_value) {}
explicit SnapshotCompression(std::string snapshot_compression)
: detail::StringTag<SnapshotCompression>(std::move(snapshot_compression)) {}
};

std::string expiry_kind_;
std::uint64_t expiry_value_;
/// Snapshot selector for `Client::snapshot(...)`.
///
/// Use this type to choose which snapshot data the server should include.
///
/// Internally, each selected value is passed across the Rust FFI as a string.
/// Values outside the supported set are rejected by the Rust client.
/// Some Rust-side aliases may also be accepted for compatibility.
class SnapshotType final : private detail::StringTag<SnapshotType> {
public:
/// Include an overview of the filesystem structure.
static SnapshotType filesystem_overview() { return SnapshotType("filesystem_overview"); }
/// Include the list of currently running processes.
static SnapshotType process_list() { return SnapshotType("process_list"); }
/// Include CPU, memory, and other system resource usage statistics.
static SnapshotType resource_usage() { return SnapshotType("resource_usage"); }
/// Include the test snapshot used for development and testing.
static SnapshotType test() { return SnapshotType("test"); }
/// Include server logs from the configured logging directory.
static SnapshotType server_logs() { return SnapshotType("server_logs"); }
/// Include the server configuration.
static SnapshotType server_config() { return SnapshotType("server_config"); }
/// Include all available snapshot types.
static SnapshotType all() { return SnapshotType("all"); }

std::string_view snapshot_type_value() const { return value(); }

private:
explicit SnapshotType(std::string snapshot_type) : detail::StringTag<SnapshotType>(std::move(snapshot_type)) {}
};

class MaxTopicSize final {
/// Maximum retained size for a topic.
///
/// Use this type to choose whether a topic uses the server default limit, no limit, or an
/// explicit byte limit.
///
/// Internally, this value is passed across the Rust FFI as a string.
/// Values outside the supported set are rejected by the Rust client.
/// Some Rust-side aliases may also be accepted for compatibility.
class MaxTopicSize final : private detail::StringTag<MaxTopicSize> {
public:
/// Use the server's default maximum topic size.
static MaxTopicSize server_default() { return MaxTopicSize("server_default"); }
/// Disable the maximum topic size limit.
static MaxTopicSize unlimited() { return MaxTopicSize("unlimited"); }
/// Set an explicit maximum topic size in bytes.
///
/// A value of `0` is treated as `server_default()`. A value of
/// `std::numeric_limits<std::uint64_t>::max()` is treated as `unlimited()`.
/// The configured limit cannot be lower than the server's segment size.
static MaxTopicSize from_bytes(std::uint64_t bytes) {
if (bytes == 0) {
return server_default();
Expand All @@ -76,20 +158,84 @@ class MaxTopicSize final {
return MaxTopicSize(std::to_string(bytes));
}

std::string_view max_topic_size() const { return max_topic_size_; }
std::string_view max_topic_size() const { return value(); }

private:
explicit MaxTopicSize(std::string max_topic_size) : detail::StringTag<MaxTopicSize>(std::move(max_topic_size)) {}
};

// TODO(slbotbm): Add rust bindings for Identifier that will use IdKind
/// Describes whether an identifier is numeric or string-based.
///
/// Use this type to describe how an identifier is encoded.
///
/// This type is reserved for future identifier bindings and is not currently passed through the
/// Rust FFI.
class IdKind final : private detail::StringTag<IdKind> {
public:
/// A numeric identifier represented as a 32-bit integer.
static IdKind numeric() { return IdKind("numeric"); }
/// A string identifier represented by its text value.
static IdKind string() { return IdKind("string"); }

std::string_view id_kind_value() const { return value(); }

private:
explicit MaxTopicSize(std::string max_topic_size) : max_topic_size_(std::move(max_topic_size)) {}
explicit IdKind(std::string id_kind) : detail::StringTag<IdKind>(std::move(id_kind)) {}
};

std::string max_topic_size_;
/// Message expiry policy for `Client::create_topic(...)`.
///
/// Use this type to choose how long messages in a topic are retained.
///
/// `expiry_kind()` returns the selected mode. `expiry_value()` returns the associated payload:
/// the duration for `duration(micros)`, `0` for `server_default()`, or
/// `std::numeric_limits<std::uint64_t>::max()` for `never_expire()`.
///
/// Internally, this value is passed across the Rust FFI as a kind/value pair.
/// Unsupported kinds are rejected by the Rust client.
class Expiry final {
public:
/// Use the server's default message expiry policy.
static Expiry server_default() { return Expiry("server_default", 0); }
/// Keep messages until they are removed for some other reason, such as topic deletion.
static Expiry never_expire() { return Expiry("never_expire", std::numeric_limits<std::uint64_t>::max()); }
/// Expire messages after the given number of microseconds.
static Expiry duration(std::uint64_t micros) { return Expiry("duration", micros); }

std::string_view expiry_kind() const { return expiry_kind_; }
std::uint64_t expiry_value() const { return expiry_value_; }

private:
explicit Expiry(std::string expiry_kind, std::uint64_t expiry_value)
: expiry_kind_(std::move(expiry_kind)), expiry_value_(expiry_value) {}

std::string expiry_kind_;
std::uint64_t expiry_value_;
};

/// Starting position for `Client::poll_messages(...)`.
///
/// Use this type to choose where the server should begin reading messages.
///
/// `polling_strategy_kind()` returns the selected mode. `polling_strategy_value()` returns the
/// associated offset or timestamp for the parameterized modes and `0` for the others.
///
/// Internally, this value is passed across the Rust FFI as a kind/value pair.
/// Unsupported kinds are rejected by the Rust client.
class PollingStrategy final {
public:
/// Start polling from a specific message offset.
static PollingStrategy offset(std::uint64_t value) { return PollingStrategy("offset", value); }
/// Start polling from a specific timestamp.
static PollingStrategy timestamp(std::uint64_t value) { return PollingStrategy("timestamp", value); }
/// Start polling from the first message in the partition.
static PollingStrategy first() { return PollingStrategy("first", 0); }
/// Start polling from the last message currently available in the partition.
static PollingStrategy last() { return PollingStrategy("last", 0); }
/// Start polling from the next message after the stored consumer offset.
///
/// This is typically used with automatic offset commits enabled.
static PollingStrategy next() { return PollingStrategy("next", 0); }

std::string_view polling_strategy_kind() const { return polling_strategy_kind_; }
Expand All @@ -103,18 +249,4 @@ class PollingStrategy final {
std::uint64_t polling_strategy_value_;
};

// TODO(slbotbm): Add rust bindings for Identifier that will use IdKind
class IdKind final {
public:
static IdKind numeric() { return IdKind("numeric"); }
static IdKind string() { return IdKind("string"); }

std::string_view id_kind_value() const { return id_kind_; }

private:
explicit IdKind(std::string id_kind) : id_kind_(std::move(id_kind)) {}

std::string id_kind_;
};

} // namespace iggy
Loading
Loading