Metadata uses Vec[Header]. Application -bin values are raw, binary-safe Strings; wire conversion performs Base64 and preserves duplicate order.
@ grpc_metadata_new → ( Vec Header )@ grpc_metadata_free sink ( Vec Header ) metadata → vLet go of metadata now rather than at the end of its owner's scope.
@ grpc_header_clone Header header → Header@ grpc_metadata_clone ( Vec Header ) headers → ( Vec Header )@ grpc_metadata_key String key → b@ grpc_metadata_reserved String key → b@ grpc_metadata_ascii String value → b@ grpc_metadata_add ( Vec Header ) metadata s key s value → !v GrpcError@ grpc_metadata_add_binary ( Vec Header ) metadata s key ( Vec u ) value → !v GrpcError@ grpc_request_headers_check_size ( Vec Header ) headers s scheme s authority s path i limit → !v GrpcErrorThe HTTP/2 client adds these four pseudoheaders when opening a POST stream. Include their decoded sizes in the same budget as application metadata.
@ grpc_message_encode String message → String@ grpc_message_decode String message → StringMalformed percent escapes are preserved as required by the wire protocol.
: GrpcStatus { i code String message ( Vec u ) details }@ grpc_status i code s message → GrpcStatus@ grpc_status_free sink GrpcStatus status → vLet go of status now rather than at the end of its owner's scope.
@ grpc_status_parse ( Vec Header ) headers → !GrpcStatus GrpcErrorheaders must be the final trailer block, or END_STREAM initial headers for a trailers-only response. The transport decides which block is final.
@ grpc_status_headers GrpcStatus status ( Vec Header ) metadata i limit → !( Vec Header ) GrpcErrorPublic facade. Import client.nu or server.nu separately for a smaller API.
Incremental gRPC server. A GrpcServer owns protocol state, never its TcpConn. Its owner's drop releases it (a final best-effort flush of the HTTP/2 connection, then every call); nothing here is released by hand — grpc_server_free and the *_free functions are optional early releases. Unary, client streaming, server streaming, and bidirectional calls share this event API. send accepts one complete message into a bounded queue; flush writes only available HTTP/2 credit and next services the peer.
: GrpcServerLimits: GrpcServerLimits {
i max_message
i max_buffer
i max_metadata
i max_calls
i max_connection_buffer
i idle_timeout_ns
}
@ grpc_server_limits → GrpcServerLimits: GrpcServerCall: GrpcServerCall {
i stream_id
String method
GrpcDecoder decoder
i deadline_ns
b input_ended
b end_notified
b headers_sent
b output_finished
b cancelled
b accepts_gzip
i output_encoding
( Vec u ) outgoing
i outgoing_pos
( Vec Header ) trailers
b finish_requested
( Vec Header ) request_trailers
}
: GrpcServer: GrpcServer {
H2Connection transport
GrpcServerLimits limits
( Vec GrpcServerCall ) calls
i cursor
b closed
}
: GrpcServerEvent: GrpcServerEvent {
i kind
i stream_id
String method
( Vec Header ) metadata
( Vec u ) message
i code
}
@ grpc_server_event_control → i@ grpc_server_event_open → i@ grpc_server_event_message → i@ grpc_server_event_half_close → i@ grpc_server_event_cancelled → i@ grpc_server_event_closed → i@ grpc_server_event_free sink GrpcServerEvent event → vLet go of event now rather than at the end of its owner's scope.
% Drop GrpcServer { @ drop GrpcServer server → v { ( h2_conn_free . server transport ) } }The connection's last frames are flushed (best effort) and its state released; the calls go with the drop glue.
@ grpc_server_free sink GrpcServer server → vLet go of server now rather than at the end of its owner's scope.
@ grpc_server_deadline GrpcServer server i sid → !i GrpcError@ grpc_server_is_cancelled GrpcServer server i sid → b@ grpc_server_new TcpConn conn GrpcServerLimits limits → !GrpcServer GrpcError@ grpc_server_send_metadata inout GrpcServer server i sid ( Vec Header ) metadata i encoding → !v GrpcError@ grpc_server_send inout GrpcServer server i sid ( Vec u ) message → !v GrpcErrorSuccess means the message was accepted. The caller keeps its input; the server owns the encoded frame until all bytes have reached the peer.
@ grpc_server_finish inout GrpcServer server i sid GrpcStatus status ( Vec Header ) metadata → !v GrpcError@ grpc_server_next inout GrpcServer server → !GrpcServerEvent GrpcError@ grpc_server_next_until inout GrpcServer server i poll_deadline_ns → !GrpcServerEvent GrpcErrorApplication timers can wake an idle connection without cancelling its RPCs. An expired poll deadline returns control; RPC deadlines still produce cancelled events and terminal status. Zero uses the ordinary idle bound.
gRPC message framing and protocol values. Inputs are borrowed; returned buffers and GrpcError messages are owned. No protobuf schema is assumed.
: i GRPC_OK 0: i GRPC_CANCELLED 1: i GRPC_UNKNOWN 2: i GRPC_INVALID_ARGUMENT 3: i GRPC_DEADLINE_EXCEEDED 4: i GRPC_NOT_FOUND 5: i GRPC_ALREADY_EXISTS 6: i GRPC_PERMISSION_DENIED 7: i GRPC_RESOURCE_EXHAUSTED 8: i GRPC_FAILED_PRECONDITION 9: i GRPC_ABORTED 10: i GRPC_OUT_OF_RANGE 11: i GRPC_UNIMPLEMENTED 12: i GRPC_INTERNAL 13: i GRPC_UNAVAILABLE 14: i GRPC_DATA_LOSS 15: i GRPC_UNAUTHENTICATED 16: i GRPC_IDENTITY 0: i GRPC_GZIP 1: i GRPC_DEFAULT_MAX_MESSAGE 4194304: i GRPC_DEFAULT_MAX_METADATA 8192: GrpcError { i code String message }@ grpc_error i code s message → GrpcError@ grpc_error_free sink GrpcError e → vLet go of e now rather than at the end of its owner's scope.
@ grpc_code_name i code → s@ grpc_http_status i status → i@ grpc_reset_status i code → i@ grpc_encoding_name i encoding → s@ grpc_encoding s name → !i GrpcError@ grpc_content_type String value → b@ grpc_timeout_ns String value → !i GrpcErrorTimeout parsing is strict, uses every defined unit, and saturates instead of overflowing for the protocol's largest (99,999,999 hour) duration.
@ grpc_timeout_value i duration_ns → StringRound up so the wire timeout never expires before the caller's duration.
@ grpc_deadline_after i now_ns i duration_ns → i@ grpc_frame ( Vec u ) message i encoding i max_message → !( Vec u ) GrpcErrorBoth compressed and uncompressed sizes are bounded. Each message gets its own compression context, including the empty protobuf message.
: GrpcMessage { b present ( Vec u ) data }: GrpcDecoder { ( Vec u ) pending i pos i max_message i max_buffer i encoding }@ grpc_message_free sink GrpcMessage message → vLet go of message now rather than at the end of its owner's scope.
@ grpc_decoder i max_message i max_buffer i encoding → !GrpcDecoder GrpcError@ grpc_decoder_free sink GrpcDecoder d → vLet go of d now rather than at the end of its owner's scope.
@ grpc_decoder_feed inout GrpcDecoder d ( Vec u ) bytes → !v GrpcErrorAtomic on error. Call next repeatedly after each feed until present=false.
@ grpc_decoder_finish GrpcDecoder d → !v GrpcErrorCalled after draining messages when the HTTP/2 receive side ends.
HTTP/2-backed gRPC calls. A client and all its calls have one owner/driver. A GrpcClient is a handle: every copy is the same client, and each call holds one, so the transport outlives every call on it. The last owner disconnects a transport the client opened (grpc_client_connect_); one it was lent (grpc_client_from_h2) stays its owner's. A GrpcCall is released by its owner's drop, which cancels an unfinished call. Nothing here is released by hand: grpc_client_close / grpc_call_free / the _free functions are optional early releases. Sending borrows protobuf bytes. Receiving transfers an owned GrpcMessage.
: GrpcClientImpl { H2Client transport String scheme String authority b owns_transport }% Drop GrpcClientImpl% Drop GrpcClientImpl {
@ drop GrpcClientImpl c → v { ? . c owns_transport { ( h2_client_disconnect . c transport ) } {} }
}
A transport the client opened is disconnected with it; a lent one stays connected for whoever lent it. The fields (the transport handle, the strings) go with the value.
: GrpcClient { s ctl }@ GrpcClient_drop sink GrpcClient h → v: GrpcCallOptions { i timeout_ns i max_send_message i max_recv_message i max_metadata i encoding }: GrpcCall: GrpcCall {
GrpcClient client // a share: the transport stays up while the call lives
i stream_id
GrpcDecoder decoder
i max_send_message
i max_metadata
i encoding
b response_checked
b status_checked
GrpcStatus status
( Vec Header ) headers
( Vec Header ) trailers
}
: GrpcUnaryResponse { ( Vec u ) data ( Vec Header ) headers ( Vec Header ) trailers GrpcStatus status }@ grpc_call_options → GrpcCallOptions@ grpc_client_connect_h2c s host i port → !GrpcClient GrpcError@ grpc_client_connect_tls s host i port b verify → !GrpcClient GrpcError@ grpc_client_close sink GrpcClient client → vLet go of client now rather than at the end of its owner's scope (the transport closes when the last call on it is gone too).
@ grpc_call_free sink GrpcCall call → vLet go of call now rather than at the end of its owner's scope.
% Drop GrpcCall% Drop GrpcCall {
unsafe @ drop GrpcCall call → v {
: *GrpcClientImpl cl ( __GrpcClient_ptr . call client )
?? ( h2_client_cancel . cl transport . call stream_id ( h2_err_cancel ) ) { T _ → {} F _ → {} }
?? ( h2_client_release_stream . cl transport . call stream_id ) { T _ → {} F _ → {} }
}
}
Always cancels unfinished calls so application early-return releases the peer's stream resources; the decoder, the metadata and the call's share of its client go with the drop glue.
@ grpc_unary_response_free sink GrpcUnaryResponse response → vLet go of response now rather than at the end of its owner's scope.
@ grpc_unary GrpcClient client s path ( Vec u ) request ( Vec Header ) metadata GrpcCallOptions opts → !GrpcUnaryResponse GrpcError