rocketmq_remoting/protocol/command_custom_header.rs
1// Copyright 2023 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 std::any::Any;
16use std::collections::HashMap;
17
18use cheetah_string::CheetahString;
19
20use crate::rocketmq_serializable::RocketMQSerializable;
21
22pub trait CommandCustomHeader: AsAny {
23 /// Checks the fields of the implementing type.
24 ///
25 /// Returns a `Result` indicating whether the fields are valid or not.
26 /// If the fields are valid, the `Ok` variant is returned with an empty `()` value.
27 /// If the fields are invalid, an `Err` variant is returned with an associated `Error` value.
28 fn check_fields(&self) -> anyhow::Result<(), anyhow::Error> {
29 Ok(())
30 }
31
32 /// Converts the implementing type to a map.
33 ///
34 /// Returns an `Option` that contains a `HashMap` of string keys and string values,
35 /// representing the implementing type's fields.
36 /// If the conversion is successful, a non-empty map is returned.
37 /// If the conversion fails, `None` is returned.
38 fn to_map(&self) -> Option<HashMap<CheetahString, CheetahString>>;
39
40 /// Writes the provided `key` to the `out` buffer if the `value` is not empty.
41 ///
42 /// # Arguments
43 ///
44 /// * `out` - A mutable reference to a `BytesMut` buffer where the `key` will be written.
45 /// * `key` - A string slice that represents the key to be written.
46 /// * `value` - A string slice that represents the value associated with the key.
47 ///
48 /// # Behavior
49 ///
50 /// If `value` is not empty, the function will write the `key` to the `out` buffer twice,
51 /// first with a short length prefix and then with a long length prefix.
52 fn write_if_not_null(&self, out: &mut bytes::BytesMut, key: &str, value: &str) {
53 if !value.is_empty() {
54 RocketMQSerializable::write_str(out, true, key);
55 RocketMQSerializable::write_str(out, false, value);
56 }
57 }
58
59 /// A placeholder function for fast encoding.
60 ///
61 /// This function currently does nothing and can be overridden by implementing types.
62 fn encode_fast(&mut self, _out: &mut bytes::BytesMut) {}
63
64 /// A placeholder function for fast decoding.
65 ///
66 /// This function currently does nothing and can be overridden by implementing types.
67 ///
68 /// # Arguments
69 ///
70 /// * `_fields` - A reference to a `HashMap` that contains the fields to be decoded.
71 fn decode_fast(&mut self, _fields: &HashMap<CheetahString, CheetahString>) -> rocketmq_error::RocketMQResult<()> {
72 Ok(())
73 }
74
75 /// Indicates whether the implementing type supports fast codec.
76 ///
77 /// # Returns
78 ///
79 /// This function returns `false` by default, indicating that the implementing type does not
80 /// support fast codec. This can be overridden by implementing types.
81 fn support_fast_codec(&self) -> bool {
82 false
83 }
84
85 /// Retrieves the value associated with the specified field from the provided map.
86 ///
87 /// # Arguments
88 ///
89 /// * `map` - A reference to a `HashMap` containing `CheetahString` keys and values.
90 /// * `field` - A reference to a `CheetahString` representing the field to retrieve.
91 ///
92 /// # Returns
93 ///
94 /// * `Ok(CheetahString)` - If the field is found in the map, returns the associated value.
95 /// * `Err(RocketMQError::Serialization)` - If the field is not found in the map, returns an
96 /// error indicating the field is required.
97 ///
98 /// # Errors
99 ///
100 /// This function returns a `SerializationError::DecodeFailed` if the specified field is
101 /// not found in the map.
102 #[inline(always)]
103 fn get_and_check_not_none(
104 &self,
105 map: &HashMap<CheetahString, CheetahString>,
106 field: &CheetahString,
107 ) -> rocketmq_error::RocketMQResult<CheetahString> {
108 match map.get(field) {
109 Some(value) => Ok(value.clone()),
110 None => Err(rocketmq_error::RocketMQError::Serialization(
111 rocketmq_error::SerializationError::DecodeFailed {
112 format: "header",
113 message: format!("The field {field} is required."),
114 },
115 )),
116 }
117 }
118}
119
120pub trait AsAny: Any {
121 fn as_any_mut(&mut self) -> &mut dyn Any;
122
123 fn as_any(&self) -> &dyn Any;
124}
125
126impl<T: CommandCustomHeader> AsAny for T {
127 fn as_any_mut(&mut self) -> &mut dyn Any {
128 self
129 }
130
131 fn as_any(&self) -> &dyn Any {
132 self
133 }
134}
135
136pub trait FromMap {
137 type Error: From<rocketmq_error::RocketMQError>;
138
139 type Target;
140 /// Converts the implementing type from a map.
141 ///
142 /// Returns an instance of `Self::Target` that is created from the provided map.
143 fn from(map: &HashMap<CheetahString, CheetahString>) -> Result<Self::Target, Self::Error>;
144}