bluetape-rs 0.4.0

Rust backend primitives for the bluetape ecosystem.
Documentation

bluetape-rs

English | 한국어

Rust backend primitives for the bluetape ecosystem.

bluetape-rs workspace overview

bluetape-rs is a new WIP repository. It is not a port of the Kotlin/JVM bluetape4k libraries and it is not a rewrite of bluetape-go. The goal is to provide Rust-native building blocks for backend services where compile-time contracts, small native binaries, explicit error handling, and deterministic integration tests matter.

Current Status

The current release-prep package scope is the 0.4.0 workspace release. It publishes the root facade and all focused foundation, collections, async, codec, and compression crates under the same version. The 0.4.0 line starts the opt-in compression surface.

Completed foundation, 0.2.0, 0.3.0, and 0.4.0 work stays narrow:

  • define the workspace layout and release policy
  • add general helper functions for typed validation errors, strings, and small numeric checks
  • add logging and tracing support without forcing a global subscriber from library code, including scoped test capture helpers
  • add reusable test helpers for async assertions, MultithreadingTester, SuspendedJobTester, and temporary resource cleanup
  • add focused collection helpers and Tokio-first bounded task helpers for the 0.2.0 line
  • add strict hex, Base64, Base58, Base62, and UTF-8 text boundary helpers for the 0.3.0 codec line
  • add the first opt-in compression crate for gzip, zlib, deflate, zstd, lz4, and snappy in the 0.4.0 line
  • keep all APIs Rust-native instead of copying Kotlin extension APIs or Go package shapes

The 0.4.0 line publishes the latest stable workspace. The codec scope keeps the explicit bluetape-rs-codec boundary for hex, Base64, Base58, Base62, URL-safe encoding, and UTF-8 text/byte boundary helpers. The compression scope keeps algorithm dependencies behind explicit feature flags and records same-condition benchmark results before release publication.

Intended Package Families

Area Working name Purpose
Core bluetape-rs-core Typed validation errors, validation helpers, string helpers, and small numeric checks.
Logging bluetape-rs-logging Tracing setup helpers, structured fields, bounded correlation IDs, and scoped test capture.
Testing bluetape-rs-test Async assertions, MultithreadingTester, SuspendedJobTester, temporary resources, and future Testcontainers boundaries.
Collections bluetape-rs-collections Focused iterator, slice, map, grouping, chunking, and error-aware transform helpers.
Async bluetape-rs-async Tokio-first bounded task execution, timeout/deadline, cancellation, and shutdown helpers.
Encoding bluetape-rs-codec Base encoders, hex, URL-safe codecs, and small binary/text codec helpers.
Compression bluetape-rs-compression Opt-in gzip, zlib, deflate, zstd, lz4, and snappy helpers with registry-style selection.
Serialization bluetape-rs-serde Safe serializer/deserializer interfaces and test helpers around serde-compatible formats.
Testcontainers bluetape-rs-testcontainers PostgreSQL, Redis, MySQL, NATS, Kafka, and emulator fixture helpers behind explicit features.
Leader bluetape-rs-leader Redis, SQL, etcd, and Kubernetes Lease leader election.
SQL bluetape-rs-sql SQL AST, dialect rendering, bind collection, typed query construction.
SQLx bluetape-rs-sqlx SQLx executor, pool, transaction, migration, and repository adapters.
Resilience bluetape-rs-resilience Retry, timeout, circuit breaker, bulkhead, backoff, and service policies.
AWS bluetape-rs-aws Thin helpers around the official AWS SDK for Rust.
Audit bluetape-rs-audit Snapshot, diff, outbox, and event-stream primitives inspired by audit workloads.
Graph bluetape-rs-graph Graph model, bulk I/O, and backend adapters where Rust drivers are mature enough.
Text bluetape-rs-text Aho-Corasick search, blockword masking, tokenizer wrappers, and language detection.
Workshop bluetape-rs-workshop Runnable axum, Tokio, SQLx, Redis, AWS, graph, and text examples.

Design Position

Rust should provide a different value proposition from the existing libraries:

  • stronger type-level contracts for SQL, nullability, transaction scope, and dialect capabilities
  • explicit Result/Option based failure and absence handling
  • Send/Sync aware concurrency boundaries
  • low runtime overhead and small deployable binaries
  • Testcontainers-backed tests for infrastructure-facing packages

The first release should stay boring and broadly reusable: helpers, logging, and test support. Codec, compression, serialization, Testcontainers, and leader election are split into separate milestones. Relational SQL should come after Testcontainers and before resilience. Leader election should come after SQL and resilience because Redis, RDB, etcd, and Kubernetes Lease support make it a larger multi-backend track. When SQL starts, its initial shape should be an inspectable SQL AST plus SQLx execution adapter, not a full ORM.

Using The Crates

The root facade enables only core by default. Enable optional facade modules explicitly, or depend on the focused crates directly when you want a smaller dependency surface.

[dependencies]
bluetape-rs = { version = "0.4.0", features = ["logging", "codec"] }

[dev-dependencies]
bluetape-rs = { version = "0.4.0", features = ["test"] }
use bluetape_rs::{codec, core, logging};

Focused crates use underscore import names:

[dependencies]
bluetape-rs-core = "0.4.0"
bluetape-rs-logging = "0.4.0"
bluetape-rs-collections = "0.4.0"
bluetape-rs-async = "0.4.0"
bluetape-rs-codec = "0.4.0"
bluetape-rs-compression = { version = "0.4.0", default-features = false, features = ["gzip"] }

[dev-dependencies]
bluetape-rs-test = "0.4.0"
use bluetape_rs_core::require_not_blank;
use bluetape_rs_logging::CorrelationId;
use bluetape_rs_collections::{Page, iter};
use bluetape_rs_codec::{decode_hex, encode_hex_lower};
use bluetape_rs_codec::{decode_base64_url_unpadded, encode_base64_url_unpadded};
use bluetape_rs_codec::{decode_base58, encode_base58};
use bluetape_rs_compression::{CompressionAlgorithm, Compressor};
use bluetape_rs_test::TempDir;

For collection helpers:

use bluetape_rs_collections::{Page, iter};

let page = Page::with_meta(vec!["a", "b"], 0, 2, 5).unwrap();
assert_eq!(page.total_pages(), 3);

let chunks: Vec<_> = iter::chunks(1..=5, 2).unwrap().collect();
assert_eq!(chunks, vec![vec![1, 2], vec![3, 4], vec![5]]);

For Tokio task and control helpers:

[dependencies]
bluetape-rs-async = "0.4.0"
use std::time::Duration;

use bluetape_rs_async::{try_map_bounded, with_timeout};

async fn run() -> Result<(), Box<dyn std::error::Error>> {
    let doubled = try_map_bounded([1, 2, 3], 2, |value| async move {
        Ok::<_, &'static str>(value * 2)
    })
    .await?;

    assert_eq!(doubled, vec![2, 4, 6]);

    let value = with_timeout(Duration::from_millis(50), async { 42 }).await?;
    assert_eq!(value, 42);
    Ok(())
}

For codec helpers:

[dependencies]
bluetape-rs-codec = "0.4.0"

bluetape-rs-codec is the 0.4.0 crate boundary for strict hex, Base64, Base58, Base62, URL-safe encoding, and UTF-8 text/byte boundary helpers. Compression starts in the 0.4.0 milestone, and serde-oriented serialization remains deferred to 0.5.0.

use bluetape_rs_codec::{decode_hex, encode_hex_lower, encode_hex_upper};

let bytes = [0x00, 0xab, 0xff];

assert_eq!(encode_hex_lower(bytes), "00abff");
assert_eq!(encode_hex_upper(bytes), "00ABFF");
assert_eq!(
    decode_hex("00abFF").expect("valid hex"),
    vec![0x00, 0xab, 0xff]
);
use bluetape_rs_codec::{
    decode_base64, decode_base64_url_unpadded, encode_base64, encode_base64_url_unpadded,
};

assert_eq!(encode_base64(b"fo"), "Zm8=");
assert_eq!(decode_base64("Zm8=").expect("valid Base64"), b"fo");

let token = encode_base64_url_unpadded([0xfb, 0xff]);
assert_eq!(token, "-_8");
assert_eq!(
    decode_base64_url_unpadded(token).expect("valid URL-safe Base64"),
    vec![0xfb, 0xff]
);

Standard helpers use the + and / alphabet. URL-safe helpers use - and _. Function names ending in _unpadded reject = padding during decode.

use bluetape_rs_codec::{decode_base58, decode_base62, encode_base58, encode_base62};

assert_eq!(encode_base58(b"Hello, World!"), "72k1xXWG59fYdzSNoA");
assert_eq!(
    decode_base58("72k1xXWG59fYdzSNoA").expect("valid Base58"),
    b"Hello, World!"
);

assert_eq!(encode_base62(b"Hello, World!"), "1wJfrzvdbtXUOlUjUf");
assert_eq!(
    decode_base62("1wJfrzvdbtXUOlUjUf").expect("valid Base62"),
    b"Hello, World!"
);

Base58 uses the Bitcoin alphabet and preserves leading zero bytes as 1. Base62 uses 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz and preserves leading zero bytes as 0. This Base62 API is byte-oriented; integer and UUID rendering can build on top of it later.

use bluetape_rs_codec::{
    decode_base64_url_unpadded, decode_utf8_text, decode_utf8_text_lossy,
    encode_base64_url_unpadded, encode_utf8_text,
};

let token = encode_base64_url_unpadded(encode_utf8_text("blue테이프"));
assert_eq!(token, "Ymx1Ze2FjOydtO2UhA");

let bytes = decode_base64_url_unpadded(token).expect("valid URL-safe Base64");
assert_eq!(decode_utf8_text(bytes).expect("valid UTF-8"), "blue테이프");

assert_eq!(decode_utf8_text_lossy([b'a', 0xff, b'z']), "a\u{fffd}z");

decode_utf8_text rejects invalid UTF-8 with typed byte-position diagnostics. Lossy replacement is available only through the explicitly named decode_utf8_text_lossy helper. General string utilities, normalization, compression registries, and serde-oriented serialization remain outside the codec crate.

Codec public API tests live under crates/codec/tests/ so examples exercise the same crate boundary that downstream users call. Source-local tests stay limited to private implementation details.

For compression helpers:

[dependencies]
bluetape-rs-compression = { version = "0.4.0", default-features = false, features = ["gzip"] }

bluetape-rs-compression provides gzip, zlib, deflate, zstd, lz4, and snappy compressors behind additive feature flags. The default feature set is empty; select algorithms explicitly. Use features = ["all"] only for benchmarking or local comparison. The zstd feature uses the native zstd-sys build path. Decode helpers use a 64 MiB decompressed-size safety limit by default; callers can set a smaller limit or explicitly remove it for trusted inputs. Stream helpers copy from Read to Write and finish their encoder before returning, and lower-level compression_writer / decompression_reader constructors are available when callers need direct stream ownership. lz4 and snappy one-shot helpers keep block/raw payload formats; their stream helpers use framed stream formats and should round-trip through the matching stream API.

use bluetape_rs_compression::{CompressionAlgorithm, CompressionConfig};

let algorithm = CompressionAlgorithm::Gzip;
let compressed = algorithm
    .compress_with_config(
        b"{\"service\":\"blue\"}",
        CompressionConfig::new().with_level(bluetape_rs_compression::CompressionLevel::Fast),
    )
    .expect("compress");
let restored = algorithm.decompress(&compressed).expect("decompress");

assert_eq!(restored, br#"{"service":"blue"}"#);
use bluetape_rs_compression::{CompressionAlgorithm, CompressionConfig};

let algorithm = CompressionAlgorithm::Gzip;
let mut compressed = Vec::new();
algorithm
    .compress_stream(
        b"{\"service\":\"blue\"}".as_slice(),
        &mut compressed,
        CompressionConfig::new(),
    )
    .expect("compress stream");

let mut restored = Vec::new();
algorithm
    .decompress_stream(
        &compressed[..],
        &mut restored,
        CompressionConfig::new().with_max_decompressed_size(1024),
    )
    .expect("decompress stream");

assert_eq!(restored, br#"{"service":"blue"}"#);

Same-condition benchmark results compare bluetape-rs, bluetape-go, and bluetape4k-io with shared JSON, text, binary, and random payload fixtures. They are a local same-condition snapshot, not a production ranking or regression threshold.

Compression throughput

Compression ratio

See the compression benchmark report and benchmark metadata for raw CSV files, fixture hashes, source revisions, run commands, caveats, and large-payload plus full compress/decompress matrix tables.

Development

cargo fmt --all
cargo test --workspace
cargo test --workspace --all-features
cargo clippy --workspace --all-targets --all-features -- -D warnings

Project Management

Project Rules

  • Keep APIs idiomatic to Rust.
  • Do not mechanically port Kotlin/JVM or Go APIs.
  • Prefer focused crates over a catch-all utility package.
  • Add real container-backed smoke tests before claiming infrastructure support.
  • Keep public documentation in English and maintain Korean README parity.