rocketmq_remoting/protocol/command_custom_header.rs
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17use std::any::Any;
18use std::collections::HashMap;
19
20use cheetah_string::CheetahString;
21use rocketmq_error::RocketmqError;
22
23use crate::rocketmq_serializable::RocketMQSerializable;
24
25pub trait CommandCustomHeader: AsAny {
26 /// Checks the fields of the implementing type.
27 ///
28 /// Returns a `Result` indicating whether the fields are valid or not.
29 /// If the fields are valid, the `Ok` variant is returned with an empty `()` value.
30 /// If the fields are invalid, an `Err` variant is returned with an associated `Error` value.
31 fn check_fields(&self) -> anyhow::Result<(), anyhow::Error> {
32 Ok(())
33 }
34
35 /// Converts the implementing type to a map.
36 ///
37 /// Returns an `Option` that contains a `HashMap` of string keys and string values,
38 /// representing the implementing type's fields.
39 /// If the conversion is successful, a non-empty map is returned.
40 /// If the conversion fails, `None` is returned.
41 fn to_map(&self) -> Option<HashMap<CheetahString, CheetahString>>;
42
43 /// Writes the provided `key` to the `out` buffer if the `value` is not empty.
44 ///
45 /// # Arguments
46 ///
47 /// * `out` - A mutable reference to a `BytesMut` buffer where the `key` will be written.
48 /// * `key` - A string slice that represents the key to be written.
49 /// * `value` - A string slice that represents the value associated with the key.
50 ///
51 /// # Behavior
52 ///
53 /// If `value` is not empty, the function will write the `key` to the `out` buffer twice,
54 /// first with a short length prefix and then with a long length prefix.
55 fn write_if_not_null(&self, out: &mut bytes::BytesMut, key: &str, value: &str) {
56 if !value.is_empty() {
57 RocketMQSerializable::write_str(out, true, key);
58 RocketMQSerializable::write_str(out, false, value);
59 }
60 }
61
62 /// A placeholder function for fast encoding.
63 ///
64 /// This function currently does nothing and can be overridden by implementing types.
65 fn encode_fast(&mut self, _out: &mut bytes::BytesMut) {}
66
67 /// A placeholder function for fast decoding.
68 ///
69 /// This function currently does nothing and can be overridden by implementing types.
70 ///
71 /// # Arguments
72 ///
73 /// * `_fields` - A reference to a `HashMap` that contains the fields to be decoded.
74 fn decode_fast(
75 &mut self,
76 _fields: &HashMap<CheetahString, CheetahString>,
77 ) -> rocketmq_error::RocketMQResult<()> {
78 Ok(())
79 }
80
81 /// Indicates whether the implementing type supports fast codec.
82 ///
83 /// # Returns
84 ///
85 /// This function returns `false` by default, indicating that the implementing type does not
86 /// support fast codec. This can be overridden by implementing types.
87 fn support_fast_codec(&self) -> bool {
88 false
89 }
90
91 /// Retrieves the value associated with the specified field from the provided map.
92 ///
93 /// # Arguments
94 ///
95 /// * `map` - A reference to a `HashMap` containing `CheetahString` keys and values.
96 /// * `field` - A reference to a `CheetahString` representing the field to retrieve.
97 ///
98 /// # Returns
99 ///
100 /// * `Ok(CheetahString)` - If the field is found in the map, returns the associated value.
101 /// * `Err(RocketmqError::DeserializeHeaderError)` - If the field is not found in the map,
102 /// returns an error indicating the field is required.
103 ///
104 /// # Errors
105 ///
106 /// This function returns a `RocketmqError::DeserializeHeaderError` if the specified field is
107 /// not found in the map.
108 #[inline(always)]
109 fn get_and_check_not_none(
110 &self,
111 map: &HashMap<CheetahString, CheetahString>,
112 field: &CheetahString,
113 ) -> rocketmq_error::RocketMQResult<CheetahString> {
114 match map.get(field) {
115 Some(value) => Ok(value.clone()),
116 None => Err(rocketmq_error::RocketmqError::DeserializeHeaderError(
117 format!("The field {field} is required."),
118 )),
119 }
120 }
121}
122
123pub trait AsAny: Any {
124 fn as_any_mut(&mut self) -> &mut dyn Any;
125
126 fn as_any(&self) -> &dyn Any;
127}
128
129impl<T: CommandCustomHeader> AsAny for T {
130 fn as_any_mut(&mut self) -> &mut dyn Any {
131 self
132 }
133
134 fn as_any(&self) -> &dyn Any {
135 self
136 }
137}
138
139pub trait FromMap {
140 type Error: From<RocketmqError>;
141
142 type Target;
143 /// Converts the implementing type from a map.
144 ///
145 /// Returns an instance of `Self::Target` that is created from the provided map.
146 fn from(map: &HashMap<CheetahString, CheetahString>) -> Result<Self::Target, Self::Error>;
147}