Skip to content

Code Generation

brec generates code in two stages:

  • When the #[block] macro is used, it generates code specific to the corresponding block.
    The same applies to the #[payload] macro, which generates code related to a specific payload type.

  • However, the protocol also requires unified types such as enum Block (enumerating all user-defined blocks)
    and enum Payload (enumerating all payloads). These general-purpose enums allow the system to handle
    various blocks and payloads dynamically.

To generate this unified code, the generate!() macro must be invoked:

pub use blocks::*;
pub use payloads::*;

brec::generate!();

This macro must be called exactly once per crate and is responsible for:

  • Implementing required brec traits for all user-defined Block types
  • Implementing required brec traits for all user-defined Payload types
  • Generating unified enums for blocks: enum Block { ... }
  • Generating unified enums for payloads: enum Payload { ... }
  • Implementing ProtocolSchema for the generated Payload enum
  • Exporting several convenience type aliases to simplify usage

When context types are declared with #[context], generate!() also constructs the crate-local ProtocolContext<'a> type. See Protocol Context.

Generated Protocol Schema

The generated Payload enum is also the protocol-level schema carrier. Its ProtocolSchema implementation binds runtime context and resource limits to the generated packet API:

impl brec::ProtocolSchema for Payload {
    type Context<'a> = ProtocolContext<'a>;

    const MAX_PAYLOAD_LEN: u32 = brec::DEFAULT_MAX_PAYLOAD_LEN;
    const MAX_PACKET_LEN: u64 = brec::DEFAULT_MAX_PACKET_LEN;
    const INITIAL_PACKET_BUFFER_CAPACITY: usize =
        brec::DEFAULT_INITIAL_PACKET_BUFFER_CAPACITY;
}

MAX_PAYLOAD_LEN limits the payload body length accepted by payload readers and writers. MAX_PACKET_LEN limits the packet body length accepted by packet readers before they buffer or wait for a complete packet. INITIAL_PACKET_BUFFER_CAPACITY controls only the initial allocation used by PacketBufReader; it is capped by the payload limit and can grow as needed within the configured packet limits.

Generated Aliases

The macro defines the following aliases to reduce verbosity when using brec types:

Alias Expanded to
Packet PacketDef<Block, Payload, Payload>
BorrowedPacketBufReader<'a, R, WorkflowCtx = ()> PacketBufReaderDef<'a, R, Block, BlockReferred<'a>, Payload, Payload, WorkflowCtx>
PacketBufReader<'a, R, WorkflowCtx = ()> same as BorrowedPacketBufReader<'a, R, WorkflowCtx>
PeekedBlocks<'a> PeekedBlocksDef<'a, BlockReferred<'a>>
PeekedBlock<'a> PeekedBlockDef<'a, BlockReferred<'a>>
BorrowedRules<'a, WorkflowCtx = ()> RulesDef<Block, BlockReferred<'a>, Payload, Payload, WorkflowCtx>
Rules<'a, WorkflowCtx = ()> same as BorrowedRules<'a, WorkflowCtx>
BorrowedRule<'a, WorkflowCtx = ()> RuleDef<Block, BlockReferred<'a>, Payload, Payload, WorkflowCtx>
Rule<'a, WorkflowCtx = ()> same as BorrowedRule<'a, WorkflowCtx>
RuleFnDef<D, S> RuleFnDef<D, S>
BorrowedReader<'a, S> ReaderDef<S, Block, BlockReferred<'a>, Payload, Payload>
Reader<S> ReaderDef<S, Block, BlockReferred<'static>, Payload, Payload>
Writer<S> WriterDef<S, Block, Payload, Payload>

These aliases make it easier to work with generated structures and remove the need to repeat generic parameters.

When brec is built with the observer feature, the macro also generates:

Alias Expanded to
SubscriptionUpdate brec::SubscriptionUpdate
SubscriptionErrorAction brec::SubscriptionErrorAction
Subscription local facade over SubscriptionDef<Block, BlockReferred<'static>, Payload, Payload, ()>
FileObserverOptions<S> local wrapper over brec::FileObserverOptions<..., SubscriptionWrapper<S>>
FileObserver local wrapper over FileObserverDef<Block, BlockReferred<'static>, Payload, Payload, ()>
FileObserverStream brec::FileObserverStreamDef<Block, BlockReferred<'static>, Payload, Payload, ()>

Subscription uses on_* callbacks: on_update, on_packet, on_error, on_stopped, on_aborted.

Usage Constraints

  • The macro must only be called once per crate. Calling it more than once will result in compilation errors due to duplicate types and impls.
  • The macro must see all relevant types (Block, Payload) in scope. You must ensure they are visible in the location where you call the macro.

Visibility Requirements

Ensure that all blocks and payloads are imported at the location where the macro is used:

pub use blocks::*;
pub use payloads::*;

brec::generate!();

Parameters

The macro can be used with the following parameters:

  • no_default_payload - Disables the built-in payloads (String and Vec<u8>).
    This has no impact on runtime performance but may slightly improve compile times and reduce binary size.

  • payloads_derive = "Trait" -
    By default, brec automatically collects all derive attributes that are common across user-defined payloads and applies them to the generated Payload enum.
    This parameter allows you to manually specify additional derives for the Payload enum-useful if you are only using the built-in payloads (String, Vec<u8>) and do not define custom ones.

  • default_max_payload_len = N - Sets Payload::MAX_PAYLOAD_LEN. The default is brec::DEFAULT_MAX_PAYLOAD_LEN (1 MiB). Payload headers and payload write paths reject payload bodies larger than this value.

  • default_max_packet_len = N - Sets Payload::MAX_PACKET_LEN. The default is brec::DEFAULT_MAX_PACKET_LEN, currently DEFAULT_MAX_PAYLOAD_LEN * 2. Packet readers reject packet bodies larger than this value before buffering or allocation-heavy processing.

  • default_initial_packet_buffer_capacity = N - Sets Payload::INITIAL_PACKET_BUFFER_CAPACITY. The default is brec::DEFAULT_INITIAL_PACKET_BUFFER_CAPACITY (64 KiB). This is a preallocation hint for PacketBufReader, not a protocol validity limit.

These size parameters currently accept integer literals.

For example,

pub use blocks::*;

// You don't define any custom payloads and only want to use the built-in ones (`String`, `Vec<u8>`)
brec::generate!(payloads_derive = "Debug, Clone");
pub use blocks::*;

// You don't define any payloads and explicitly disable the built-in ones
brec::generate!(no_default_payload);
pub use blocks::*;
pub use payloads::*;

brec::generate!(
    default_max_payload_len = 4_194_304,
    default_max_packet_len = 8_388_608,
    default_initial_packet_buffer_capacity = 131_072,
);

If the user fully disables payload support (as in the example above), the macro will not generate any packet-related types (see Generated Aliases).