protocrap 0.3.2

A small, efficient, and flexible protobuf implementation
Documentation
load("@bazel_skylib//rules:diff_test.bzl", "diff_test")
load("@rules_rust//rust:defs.bzl", "rust_library", "rust_binary", "rust_test", "rust_doc_test")
load("//bazel:proto_descriptor_set.bzl", "proto_descriptor_set")

exports_files([
    "Cargo.toml",
    "Cargo.lock",
    ".cargo/config.toml",
])

# Main protocrap library
rust_library(
    name = "protocrap",
    srcs = glob(
        ["src/**/*.rs"],
        exclude = ["src/main.rs", "src/codegen/**"],
    ),
    crate_features = [
        "std",
        "serde_support",
    ],
    edition = "2024",
    visibility = ["//visibility:public"],
    deps = [
        "@crates//:allocator-api2",
        "@crates//:base64",
        "@crates//:futures",
        "@crates//:serde",
        "@crates//:time",
    ],
)

# Protocrap codegen binary
rust_binary(
    name = "protocrap-codegen",
    srcs = ["src/main.rs"] + glob(["src/codegen/*.rs"]),
    crate_features = ["bazel"],
    edition = "2024",
    visibility = ["//visibility:public"],
    deps = [
        ":protocrap",
        "@crates//:allocator-api2",
        "@crates//:anyhow",
        "@crates//:prettyplease",
        "@crates//:proc-macro2",
        "@crates//:quote",
        "@crates//:serde_json",
        "@crates//:syn",
    ],
)

# Descriptor proto for codegen bootstrap
proto_descriptor_set(
    name = "descriptor_set",
    deps = [
        "@protobuf//:descriptor_proto",
    ],
    visibility = ["//visibility:public"],
)

# Unit tests for the main library
rust_test(
    name = "protocrap_test",
    crate = ":protocrap",
    crate_features = [
        "std",
        "serde_support",
    ],
)

# Test that descriptor.pc.rs is up to date with codegen
genrule(
    name = "generate_descriptor_test",
    srcs = [":descriptor_set"],
    outs = ["descriptor.pc.rs.generated"],
    cmd = "$(location :protocrap-codegen) $(location :descriptor_set) $@",
    tools = [":protocrap-codegen"],
)

diff_test(
    name = "descriptor_up_to_date_test",
    file1 = ":generate_descriptor_test",
    file2 = "src/descriptor.pc.rs",
)

# Bootstrap codegen binary (uses published protocrap from crates.io)
rust_binary(
    name = "protocrap-codegen-bootstrap",
    srcs = ["src/main.rs"] + glob(["src/codegen/*.rs"]),
    aliases = {"@crates//:protocrap": "protocrap"},
    crate_features = ["bazel"],
    edition = "2024",
    deps = [
        "@crates//:allocator-api2",
        "@crates//:anyhow",
        "@crates//:prettyplease",
        "@crates//:proc-macro2",
        "@crates//:protocrap",
        "@crates//:quote",
        "@crates//:serde_json",
        "@crates//:syn",
    ],
)

# Generate descriptor using bootstrap binary
genrule(
    name = "generate_descriptor_bootstrap",
    srcs = [":descriptor_set"],
    outs = ["descriptor.pc.rs.bootstrap"],
    cmd = "$(location :protocrap-codegen-bootstrap) $(location :descriptor_set) $@",
    tools = [":protocrap-codegen-bootstrap"],
)

# Verify bootstrap and normal codegen produce identical output
diff_test(
    name = "bootstrap_matches_test",
    file1 = ":generate_descriptor_test",
    file2 = ":generate_descriptor_bootstrap",
)

# Regenerate descriptor.pc.rs in source tree using bootstrap codegen
# Usage: bazel run //:regen_descriptor
genrule(
    name = "regen_descriptor",
    srcs = [":generate_descriptor_bootstrap"],
    outs = ["regen_descriptor_runner.sh"],
    cmd = """
echo '#!/bin/bash' > $@
echo 'cp "$(location :generate_descriptor_bootstrap)" "$$BUILD_WORKSPACE_DIRECTORY/src/descriptor.pc.rs"' >> $@
chmod +x $@
""",
    executable = True,
)

# Test that doc examples compile and pass
rust_doc_test(
    name = "doc_test",
    crate = ":protocrap",
)