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}