Skip to main content

rocketmq_protocol/protocol/header_codec/
codec.rs

1// Copyright 2026 The RocketMQ Rust Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use super::EncodeSink;
16use super::HeaderFieldSource;
17use super::HeaderFieldSpec;
18use super::HeaderFlattenSpec;
19use super::ProtocolContractViolation;
20use super::ResolvedHeaderKey;
21use crate::HeaderMap;
22
23/// Statically dispatched codec contract for an explicit request-header schema.
24///
25/// Implementations are generated by `RequestHeaderCodec`. Map and binary
26/// destinations share [`Self::encode_into`], so validation, canonical keys,
27/// Java ranges, flattening, and value conversion cannot diverge by format.
28pub trait HeaderCodec: Sized {
29    /// Stable, fully qualified Rust schema identifier.
30    const TYPE_ID: &'static str;
31    /// Rust header name used in diagnostics.
32    const HEADER_NAME: &'static str;
33    /// Fully qualified Java peer when one is declared.
34    const JAVA_CLASS: Option<&'static str>;
35    /// Recursive upper bound used to reserve map entries.
36    const FIELD_COUNT_HINT: usize;
37    /// Fields declared directly by this header, in stable binary order.
38    const LOCAL_FIELD_SPECS: &'static [HeaderFieldSpec];
39    /// Flatten groups declared directly by this header, in stable binary order.
40    const LOCAL_FLATTEN_SPECS: &'static [HeaderFlattenSpec];
41    /// Whether direct binary generation was requested for the schema.
42    const FAST_ENABLED: bool;
43
44    /// Validates this header layer before it writes to a wire destination.
45    ///
46    /// # Errors
47    ///
48    /// Returns a classified structural or header-specific validation failure.
49    fn validate_for_wire(&self) -> Result<(), ProtocolContractViolation>;
50
51    /// Appends canonical fields to a statically dispatched destination.
52    ///
53    /// # Errors
54    ///
55    /// Returns a typed validation, range, or destination representation error.
56    fn encode_into<S: EncodeSink>(&self, sink: &mut S) -> Result<(), ProtocolContractViolation>;
57
58    /// Decodes this header from borrowed extension fields.
59    ///
60    /// # Errors
61    ///
62    /// Returns a typed missing, conflict, conversion, range, or validation error.
63    fn decode_from_map(map: &HeaderMap) -> Result<Self, ProtocolContractViolation>;
64
65    /// Decodes this header directly from a borrowed field source.
66    ///
67    /// Generated request-header codecs override this method with a zero-materialization
68    /// scan. The default keeps manually implemented codecs source-compatible.
69    ///
70    /// # Errors
71    ///
72    /// Returns the same classified failures as [`Self::decode_from_map`].
73    #[inline]
74    fn decode_from_source(source: &dyn HeaderFieldSource) -> Result<Self, ProtocolContractViolation> {
75        let map = source.to_header_map();
76        Self::decode_from_map(&map)
77    }
78
79    /// Returns whether this header or any flattened child owns a present key.
80    fn contains_any_field(map: &HeaderMap) -> bool;
81
82    /// Returns whether this header or a flattened child owns a source field.
83    #[inline]
84    fn contains_any_field_source(source: &dyn HeaderFieldSource) -> bool {
85        let mut contains = false;
86        source.visit_fields_while(&mut |key, _value| {
87            if Self::contains_wire_key(key) {
88                contains = true;
89                false
90            } else {
91                true
92            }
93        });
94        contains
95    }
96
97    /// Estimates the encoded ROCKETMQ extension-field payload length.
98    ///
99    /// The result saturates at [`usize::MAX`]. It is a capacity hint and does
100    /// not validate the header or guarantee that a specific format can encode it.
101    fn encoded_len_hint(&self) -> usize;
102
103    /// Visits field schemas declared here and recursively by flattened headers.
104    fn visit_field_specs(visitor: &mut dyn FnMut(&HeaderFieldSpec));
105
106    /// Visits flatten schemas declared here and recursively by flattened headers.
107    fn visit_flatten_specs(visitor: &mut dyn FnMut(&HeaderFlattenSpec));
108
109    /// Resolves a canonical key or alias to its owning typed field.
110    fn resolve_wire_key(key: &str) -> Option<ResolvedHeaderKey>;
111
112    /// Resolves a key and returns its canonical wire key.
113    #[inline]
114    fn canonical_wire_key(key: &str) -> Option<&'static str> {
115        Self::resolve_wire_key(key).map(|resolved| resolved.canonical)
116    }
117
118    /// Returns whether a canonical key or alias belongs to this schema.
119    #[inline]
120    fn contains_wire_key(key: &str) -> bool {
121        Self::resolve_wire_key(key).is_some()
122    }
123}