mqtt_protocol_core/mqtt/connection/
sendable.rs

1// MIT License
2//
3// Copyright (c) 2025 Takatoshi Kondo
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23use crate::mqtt::common::tracing::trace;
24use crate::mqtt::connection::role;
25use crate::mqtt::connection::role::RoleType;
26use crate::mqtt::connection::sendable_role::SendableRole;
27use crate::mqtt::connection::sendable_version::SendableVersion;
28use crate::mqtt::connection::GenericConnection;
29use crate::mqtt::connection::GenericEvent;
30use crate::mqtt::packet::kind::PacketKind;
31use crate::mqtt::packet::GenericPacket;
32use crate::mqtt::packet::IsPacketId;
33use crate::mqtt::result_code::MqttError;
34use alloc::vec::Vec;
35use core::fmt::Debug;
36
37/// Core trait for sendable packets
38pub trait Sendable<Role, PacketIdType>: PacketKind
39where
40    Role: RoleType,
41    PacketIdType: IsPacketId,
42{
43    fn dispatch_send(
44        self,
45        connection: &mut GenericConnection<Role, PacketIdType>,
46    ) -> Vec<GenericEvent<PacketIdType>>;
47}
48
49/// Trait for connection send behavior
50pub trait SendBehavior<Role, PacketIdType>
51where
52    Role: RoleType,
53    PacketIdType: IsPacketId,
54{
55    fn send<T>(&mut self, packet: T) -> Vec<GenericEvent<PacketIdType>>
56    where
57        T: Sendable<Role, PacketIdType>;
58}
59
60/// Helper trait for type-specific send operations
61pub trait SendableHelper<Role, PacketIdType>: PacketKind + Sized
62where
63    Role: RoleType,
64    PacketIdType: IsPacketId,
65{
66    // v3.1.1 methods
67    fn send_connect_v3_1_1(
68        self,
69        _connection: &mut GenericConnection<Role, PacketIdType>,
70    ) -> Vec<GenericEvent<PacketIdType>> {
71        unreachable!("send_connect_v3_1_1 not implemented for this type")
72    }
73
74    fn send_connack_v3_1_1(
75        self,
76        _connection: &mut GenericConnection<Role, PacketIdType>,
77    ) -> Vec<GenericEvent<PacketIdType>> {
78        unreachable!("send_connack_v3_1_1 not implemented for this type")
79    }
80
81    fn send_publish_v3_1_1(
82        self,
83        _connection: &mut GenericConnection<Role, PacketIdType>,
84    ) -> Vec<GenericEvent<PacketIdType>> {
85        unreachable!("send_publish_v3_1_1 not implemented for this type")
86    }
87
88    fn send_puback_v3_1_1(
89        self,
90        _connection: &mut GenericConnection<Role, PacketIdType>,
91    ) -> Vec<GenericEvent<PacketIdType>> {
92        unreachable!("send_puback_v3_1_1 not implemented for this type")
93    }
94
95    fn send_pubrec_v3_1_1(
96        self,
97        _connection: &mut GenericConnection<Role, PacketIdType>,
98    ) -> Vec<GenericEvent<PacketIdType>> {
99        unreachable!("send_pubrec_v3_1_1 not implemented for this type")
100    }
101
102    fn send_pubrel_v3_1_1(
103        self,
104        _connection: &mut GenericConnection<Role, PacketIdType>,
105    ) -> Vec<GenericEvent<PacketIdType>> {
106        unreachable!("send_pubrel_v3_1_1 not implemented for this type")
107    }
108
109    fn send_pubcomp_v3_1_1(
110        self,
111        _connection: &mut GenericConnection<Role, PacketIdType>,
112    ) -> Vec<GenericEvent<PacketIdType>> {
113        unreachable!("send_pubcomp_v3_1_1 not implemented for this type")
114    }
115
116    fn send_subscribe_v3_1_1(
117        self,
118        _connection: &mut GenericConnection<Role, PacketIdType>,
119    ) -> Vec<GenericEvent<PacketIdType>> {
120        unreachable!("send_subscribe_v3_1_1 not implemented for this type")
121    }
122
123    fn send_suback_v3_1_1(
124        self,
125        _connection: &mut GenericConnection<Role, PacketIdType>,
126    ) -> Vec<GenericEvent<PacketIdType>> {
127        unreachable!("send_suback_v3_1_1 not implemented for this type")
128    }
129
130    fn send_unsubscribe_v3_1_1(
131        self,
132        _connection: &mut GenericConnection<Role, PacketIdType>,
133    ) -> Vec<GenericEvent<PacketIdType>> {
134        unreachable!("send_unsubscribe_v3_1_1 not implemented for this type")
135    }
136
137    fn send_unsuback_v3_1_1(
138        self,
139        _connection: &mut GenericConnection<Role, PacketIdType>,
140    ) -> Vec<GenericEvent<PacketIdType>> {
141        unreachable!("send_unsuback_v3_1_1 not implemented for this type")
142    }
143
144    fn send_pingreq_v3_1_1(
145        self,
146        _connection: &mut GenericConnection<Role, PacketIdType>,
147    ) -> Vec<GenericEvent<PacketIdType>> {
148        unreachable!("send_pingreq_v3_1_1 not implemented for this type")
149    }
150
151    fn send_pingresp_v3_1_1(
152        self,
153        _connection: &mut GenericConnection<Role, PacketIdType>,
154    ) -> Vec<GenericEvent<PacketIdType>> {
155        unreachable!("send_pingresp_v3_1_1 not implemented for this type")
156    }
157
158    fn send_disconnect_v3_1_1(
159        self,
160        _connection: &mut GenericConnection<Role, PacketIdType>,
161    ) -> Vec<GenericEvent<PacketIdType>> {
162        unreachable!("send_disconnect_v3_1_1 not implemented for this type")
163    }
164
165    // v5.0 methods
166    fn send_connect_v5_0(
167        self,
168        _connection: &mut GenericConnection<Role, PacketIdType>,
169    ) -> Vec<GenericEvent<PacketIdType>> {
170        unreachable!("send_connect_v5_0 not implemented for this type")
171    }
172
173    fn send_connack_v5_0(
174        self,
175        _connection: &mut GenericConnection<Role, PacketIdType>,
176    ) -> Vec<GenericEvent<PacketIdType>> {
177        unreachable!("send_connack_v5_0 not implemented for this type")
178    }
179
180    fn send_publish_v5_0(
181        self,
182        _connection: &mut GenericConnection<Role, PacketIdType>,
183    ) -> Vec<GenericEvent<PacketIdType>> {
184        unreachable!("send_publish_v5_0 not implemented for this type")
185    }
186
187    fn send_puback_v5_0(
188        self,
189        _connection: &mut GenericConnection<Role, PacketIdType>,
190    ) -> Vec<GenericEvent<PacketIdType>> {
191        unreachable!("send_puback_v5_0 not implemented for this type")
192    }
193
194    fn send_pubrec_v5_0(
195        self,
196        _connection: &mut GenericConnection<Role, PacketIdType>,
197    ) -> Vec<GenericEvent<PacketIdType>> {
198        unreachable!("send_pubrec_v5_0 not implemented for this type")
199    }
200
201    fn send_pubrel_v5_0(
202        self,
203        _connection: &mut GenericConnection<Role, PacketIdType>,
204    ) -> Vec<GenericEvent<PacketIdType>> {
205        unreachable!("send_pubrel_v5_0 not implemented for this type")
206    }
207
208    fn send_pubcomp_v5_0(
209        self,
210        _connection: &mut GenericConnection<Role, PacketIdType>,
211    ) -> Vec<GenericEvent<PacketIdType>> {
212        unreachable!("send_pubcomp_v5_0 not implemented for this type")
213    }
214
215    fn send_subscribe_v5_0(
216        self,
217        _connection: &mut GenericConnection<Role, PacketIdType>,
218    ) -> Vec<GenericEvent<PacketIdType>> {
219        unreachable!("send_subscribe_v5_0 not implemented for this type")
220    }
221
222    fn send_suback_v5_0(
223        self,
224        _connection: &mut GenericConnection<Role, PacketIdType>,
225    ) -> Vec<GenericEvent<PacketIdType>> {
226        unreachable!("send_suback_v5_0 not implemented for this type")
227    }
228
229    fn send_unsubscribe_v5_0(
230        self,
231        _connection: &mut GenericConnection<Role, PacketIdType>,
232    ) -> Vec<GenericEvent<PacketIdType>> {
233        unreachable!("send_unsubscribe_v5_0 not implemented for this type")
234    }
235
236    fn send_unsuback_v5_0(
237        self,
238        _connection: &mut GenericConnection<Role, PacketIdType>,
239    ) -> Vec<GenericEvent<PacketIdType>> {
240        unreachable!("send_unsuback_v5_0 not implemented for this type")
241    }
242
243    fn send_pingreq_v5_0(
244        self,
245        _connection: &mut GenericConnection<Role, PacketIdType>,
246    ) -> Vec<GenericEvent<PacketIdType>> {
247        unreachable!("send_pingreq_v5_0 not implemented for this type")
248    }
249
250    fn send_pingresp_v5_0(
251        self,
252        _connection: &mut GenericConnection<Role, PacketIdType>,
253    ) -> Vec<GenericEvent<PacketIdType>> {
254        unreachable!("send_pingresp_v5_0 not implemented for this type")
255    }
256
257    fn send_disconnect_v5_0(
258        self,
259        _connection: &mut GenericConnection<Role, PacketIdType>,
260    ) -> Vec<GenericEvent<PacketIdType>> {
261        unreachable!("send_disconnect_v5_0 not implemented for this type")
262    }
263
264    fn send_auth_v5_0(
265        self,
266        _connection: &mut GenericConnection<Role, PacketIdType>,
267    ) -> Vec<GenericEvent<PacketIdType>> {
268        unreachable!("send_auth_v5_0 not implemented for this type")
269    }
270}
271
272// Generic implementation for specific packet types with compile-time dispatch
273impl<Role, PacketIdType, T> Sendable<Role, PacketIdType> for T
274where
275    Role: role::RoleType,
276    PacketIdType: IsPacketId,
277    T: SendableRole<Role>
278        + SendableVersion
279        + core::fmt::Display
280        + Debug
281        + PacketKind
282        + SendableHelper<Role, PacketIdType>,
283{
284    fn dispatch_send(
285        self,
286        connection: &mut GenericConnection<Role, PacketIdType>,
287    ) -> Vec<GenericEvent<PacketIdType>> {
288        // Version check first
289        if !T::check(&connection.get_protocol_version()) {
290            return vec![GenericEvent::NotifyError(MqttError::VersionMismatch)];
291        }
292
293        trace!("Static dispatch sent: {}", self);
294        // Compile-time dispatch based on packet type and version
295        // The compiler will eliminate unused branches for specific types
296        if T::IS_CONNECT {
297            if T::IS_V3_1_1 {
298                self.send_connect_v3_1_1(connection)
299            } else if T::IS_V5_0 {
300                self.send_connect_v5_0(connection)
301            } else {
302                unreachable!("Invalid version for CONNECT packet")
303            }
304        } else if T::IS_CONNACK {
305            if T::IS_V3_1_1 {
306                self.send_connack_v3_1_1(connection)
307            } else if T::IS_V5_0 {
308                self.send_connack_v5_0(connection)
309            } else {
310                unreachable!("Invalid version for CONNACK packet")
311            }
312        } else if T::IS_PUBLISH {
313            if T::IS_V3_1_1 {
314                self.send_publish_v3_1_1(connection)
315            } else if T::IS_V5_0 {
316                self.send_publish_v5_0(connection)
317            } else {
318                unreachable!("Invalid version for PUBLISH packet")
319            }
320        } else if T::IS_PUBACK {
321            if T::IS_V3_1_1 {
322                self.send_puback_v3_1_1(connection)
323            } else if T::IS_V5_0 {
324                self.send_puback_v5_0(connection)
325            } else {
326                unreachable!("Invalid version for PUBACK packet")
327            }
328        } else if T::IS_PUBREC {
329            if T::IS_V3_1_1 {
330                self.send_pubrec_v3_1_1(connection)
331            } else if T::IS_V5_0 {
332                self.send_pubrec_v5_0(connection)
333            } else {
334                unreachable!("Invalid version for PUBREC packet")
335            }
336        } else if T::IS_PUBREL {
337            if T::IS_V3_1_1 {
338                self.send_pubrel_v3_1_1(connection)
339            } else if T::IS_V5_0 {
340                self.send_pubrel_v5_0(connection)
341            } else {
342                unreachable!("Invalid version for PUBREL packet")
343            }
344        } else if T::IS_PUBCOMP {
345            if T::IS_V3_1_1 {
346                self.send_pubcomp_v3_1_1(connection)
347            } else if T::IS_V5_0 {
348                self.send_pubcomp_v5_0(connection)
349            } else {
350                unreachable!("Invalid version for PUBCOMP packet")
351            }
352        } else if T::IS_SUBSCRIBE {
353            if T::IS_V3_1_1 {
354                self.send_subscribe_v3_1_1(connection)
355            } else if T::IS_V5_0 {
356                self.send_subscribe_v5_0(connection)
357            } else {
358                unreachable!("Invalid version for SUBSCRIBE packet")
359            }
360        } else if T::IS_SUBACK {
361            if T::IS_V3_1_1 {
362                self.send_suback_v3_1_1(connection)
363            } else if T::IS_V5_0 {
364                self.send_suback_v5_0(connection)
365            } else {
366                unreachable!("Invalid version for SUBACK packet")
367            }
368        } else if T::IS_UNSUBSCRIBE {
369            if T::IS_V3_1_1 {
370                self.send_unsubscribe_v3_1_1(connection)
371            } else if T::IS_V5_0 {
372                self.send_unsubscribe_v5_0(connection)
373            } else {
374                unreachable!("Invalid version for UNSUBSCRIBE packet")
375            }
376        } else if T::IS_UNSUBACK {
377            if T::IS_V3_1_1 {
378                self.send_unsuback_v3_1_1(connection)
379            } else if T::IS_V5_0 {
380                self.send_unsuback_v5_0(connection)
381            } else {
382                unreachable!("Invalid version for UNSUBACK packet")
383            }
384        } else if T::IS_PINGREQ {
385            if T::IS_V3_1_1 {
386                self.send_pingreq_v3_1_1(connection)
387            } else if T::IS_V5_0 {
388                self.send_pingreq_v5_0(connection)
389            } else {
390                unreachable!("Invalid version for PINGREQ packet")
391            }
392        } else if T::IS_PINGRESP {
393            if T::IS_V3_1_1 {
394                self.send_pingresp_v3_1_1(connection)
395            } else if T::IS_V5_0 {
396                self.send_pingresp_v5_0(connection)
397            } else {
398                unreachable!("Invalid version for PINGRESP packet")
399            }
400        } else if T::IS_DISCONNECT {
401            if T::IS_V3_1_1 {
402                self.send_disconnect_v3_1_1(connection)
403            } else if T::IS_V5_0 {
404                self.send_disconnect_v5_0(connection)
405            } else {
406                unreachable!("Invalid version for DISCONNECT packet")
407            }
408        } else if T::IS_AUTH {
409            if T::IS_V5_0 {
410                self.send_auth_v5_0(connection)
411            } else {
412                unreachable!("AUTH packet is only valid for v5.0")
413            }
414        } else {
415            unreachable!("Unknown packet type")
416        }
417    }
418}
419
420// Sendable implementation for GenericPacket (runtime dispatch)
421impl<PacketIdType> Sendable<role::Client, PacketIdType> for GenericPacket<PacketIdType>
422where
423    PacketIdType: IsPacketId,
424{
425    fn dispatch_send(
426        self,
427        connection: &mut GenericConnection<role::Client, PacketIdType>,
428    ) -> Vec<GenericEvent<PacketIdType>> {
429        connection.send(self)
430    }
431}
432
433impl<PacketIdType> Sendable<role::Server, PacketIdType> for GenericPacket<PacketIdType>
434where
435    PacketIdType: IsPacketId,
436{
437    fn dispatch_send(
438        self,
439        connection: &mut GenericConnection<role::Server, PacketIdType>,
440    ) -> Vec<GenericEvent<PacketIdType>> {
441        connection.send(self)
442    }
443}
444
445impl<PacketIdType> Sendable<role::Any, PacketIdType> for GenericPacket<PacketIdType>
446where
447    PacketIdType: IsPacketId,
448{
449    fn dispatch_send(
450        self,
451        connection: &mut GenericConnection<role::Any, PacketIdType>,
452    ) -> Vec<GenericEvent<PacketIdType>> {
453        connection.send(self)
454    }
455}