Skip to main content

rsomeip_proto/
interface.rs

1//! SOME/IP service interface.
2
3use crate::{InterfaceVersion, Message, MessageType, MethodId, ReturnCode};
4use std::collections::HashMap;
5
6/// SOME/IP service interface.
7///
8/// An interface defines a series of methods which determine the types of messages that it can send or
9/// receive. These methods can differ between successive versions of the interface.
10///
11/// This struct is used to manage the state of a service interface by defining its methods, and
12/// checking incoming and outgoing messages for correctness.
13///
14/// # Stub vs Proxy
15///
16/// An interface can behave either as a stub which serves methods to be "called", or as a proxy which
17/// "calls" these methods. This determines what kind of message types the interface considers valid
18/// for a given method type.
19#[derive(Debug, Default, Clone, PartialEq, Eq)]
20pub struct Interface {
21    /// Major version of the service interface.
22    pub version: InterfaceVersion,
23    /// Whether the interface should behave as a stub or proxy.
24    pub flavor: InterfaceType,
25    /// Methods registered with the interface.
26    pub methods: HashMap<MethodId, MethodType>,
27}
28
29impl Interface {
30    /// Returns `self` as a [`Stub`].
31    ///
32    /// # Examples
33    ///
34    /// ```rust
35    /// use rsomeip_proto::{Interface, InterfaceType};
36    ///
37    /// let interface = Interface::default().into_stub();
38    /// assert_eq!(interface.flavor, InterfaceType::Stub);
39    /// ```
40    ///
41    /// [`Stub`]: InterfaceType::Stub
42    #[inline]
43    #[must_use]
44    pub const fn into_stub(mut self) -> Self {
45        self.flavor = InterfaceType::Stub;
46        self
47    }
48
49    /// Returns `self` as a [`Proxy`].
50    ///
51    /// # Examples
52    ///
53    /// ```rust
54    /// use rsomeip_proto::{Interface, InterfaceType};
55    ///
56    /// let interface = Interface::default().into_proxy();
57    /// assert_eq!(interface.flavor, InterfaceType::Proxy);
58    /// ```
59    ///
60    /// [`Proxy`]: InterfaceType::Proxy
61    #[inline]
62    #[must_use]
63    pub const fn into_proxy(mut self) -> Self {
64        self.flavor = InterfaceType::Proxy;
65        self
66    }
67
68    /// Returns `self` with the given [`InterfaceVersion`].
69    ///
70    /// # Examples
71    ///
72    /// ```rust
73    /// use rsomeip_proto::{Interface, InterfaceVersion};
74    ///
75    /// let interface = Interface::default().with_version(InterfaceVersion::new(1));
76    /// assert_eq!(interface.version, InterfaceVersion::new(1));
77    /// ```
78    #[inline]
79    #[must_use]
80    pub const fn with_version(mut self, version: InterfaceVersion) -> Self {
81        self.version = version;
82        self
83    }
84
85    /// Returns `self` with the given method.
86    ///
87    /// This is the same as inserting a method with [`MethodType::Method`].
88    ///
89    /// # Examples
90    ///
91    /// ```rust
92    /// use rsomeip_proto::{Interface, MethodId, MethodType};
93    ///
94    /// let interface = Interface::default().with_method(MethodId::new(1));
95    /// assert_eq!(interface.get(MethodId::new(1)), Some(MethodType::Method));
96    /// ```
97    #[inline]
98    #[must_use]
99    pub fn with_method(mut self, id: MethodId) -> Self {
100        _ = self.insert(id, MethodType::Method);
101        self
102    }
103
104    /// Returns `self` with the given procedure.
105    ///
106    /// This is the same as inserting a method with [`MethodType::Procedure`].
107    ///
108    /// # Examples
109    ///
110    /// ```rust
111    /// use rsomeip_proto::{Interface, MethodId, MethodType};
112    ///
113    /// let interface = Interface::default().with_procedure(MethodId::new(1));
114    /// assert_eq!(interface.get(MethodId::new(1)), Some(MethodType::Procedure));
115    /// ```
116    #[inline]
117    #[must_use]
118    pub fn with_procedure(mut self, id: MethodId) -> Self {
119        _ = self.insert(id, MethodType::Procedure);
120        self
121    }
122
123    /// Returns `self` with the given event.
124    ///
125    /// This is the same as inserting a method with [`MethodType::Event`].
126    ///
127    /// # Examples
128    ///
129    /// ```rust
130    /// use rsomeip_proto::{Interface, MethodId, MethodType};
131    ///
132    /// let interface = Interface::default().with_event(MethodId::new(1));
133    /// assert_eq!(interface.get(MethodId::new(1)), Some(MethodType::Event));
134    /// ```
135    #[inline]
136    #[must_use]
137    pub fn with_event(mut self, id: MethodId) -> Self {
138        _ = self.insert(id, MethodType::Event);
139        self
140    }
141
142    /// Inserts a method with the given `id` and `flavor`.
143    ///
144    /// Returns the previous flavor.
145    ///
146    /// # Examples
147    ///
148    /// ```rust
149    /// use rsomeip_proto::{Interface, MethodId, MethodType};
150    ///
151    /// let mut interface = Interface::default();
152    /// assert_eq!(interface.insert(MethodId::new(1), MethodType::Method), None);
153    /// assert_eq!(interface.insert(MethodId::new(1), MethodType::Procedure), Some(MethodType::Method));
154    /// ```
155    #[inline]
156    pub fn insert(&mut self, id: MethodId, flavor: MethodType) -> Option<MethodType> {
157        self.methods.insert(id, flavor)
158    }
159
160    /// Removes the method with the given `id`.
161    ///
162    /// # Examples
163    ///
164    /// ```rust
165    /// use rsomeip_proto::{Interface, MethodId, MethodType};
166    ///
167    /// let mut interface = Interface::default().with_method(MethodId::new(1));
168    /// assert_eq!(interface.remove(MethodId::new(1)), Some(MethodType::Method));
169    /// assert_eq!(interface.remove(MethodId::new(1)), None);
170    /// ```
171    #[inline]
172    pub fn remove(&mut self, id: MethodId) -> Option<MethodType> {
173        self.methods.remove(&id)
174    }
175
176    /// Returns the flavor of the method with the given `id`.
177    ///
178    /// # Examples
179    ///
180    /// ```rust
181    /// use rsomeip_proto::{Interface, MethodId, MethodType};
182    ///
183    /// let interface = Interface::default().with_method(MethodId::new(1));
184    /// assert_eq!(interface.get(MethodId::new(1)), Some(MethodType::Method));
185    /// ```
186    #[inline]
187    #[must_use]
188    pub fn get(&self, id: MethodId) -> Option<MethodType> {
189        self.methods.get(&id).copied()
190    }
191
192    /// Returns a mutable reference to the method with the given `id`.
193    ///
194    /// # Examples
195    ///
196    /// ```rust
197    /// use rsomeip_proto::{Interface, MethodId, MethodType};
198    ///
199    /// let mut interface = Interface::default().with_method(MethodId::new(1));
200    /// assert_eq!(interface.get_mut(MethodId::new(1)), Some(&mut MethodType::Method));
201    /// ```
202    #[inline]
203    #[must_use]
204    pub fn get_mut(&mut self, id: MethodId) -> Option<&mut MethodType> {
205        self.methods.get_mut(&id)
206    }
207}
208
209/// Shorthand for making an error message.
210macro_rules! drop {
211    ($reason:expr) => {
212        Err((MessageError::Dropped($reason)))
213    };
214}
215
216/// Shorthand for making an error message.
217macro_rules! invalid {
218    ($reason:expr) => {
219        Err((MessageError::Invalid($reason)))
220    };
221}
222
223/// Shorthand for making an error message.
224macro_rules! invalid_or_dropped {
225    ($message_type:expr, $reason:expr) => {
226        Err((MessageError::invalid_or_dropped($message_type, $reason)))
227    };
228}
229
230impl Interface {
231    /// Checks if the `message` is valid in the given `direction`.
232    ///
233    /// This is used to confirm that the message parameters are correctly configured for this
234    /// interface when sending ([`Direction::Outgoing`]) or receiving it ([`Direction::Incoming`]).
235    ///
236    /// # Errors
237    ///
238    /// Returns a [`MessageError`] if the message is invalid.
239    pub(crate) fn check<T>(
240        &self,
241        message: &Message<T>,
242        direction: Direction,
243    ) -> Result<(), MessageError> {
244        // Check if interface version is correct.
245        if message.interface() != self.version {
246            return invalid_or_dropped!(message.message_type(), ReturnCode::WrongInterfaceVersion);
247        }
248
249        // Check if the method is registered.
250        let Some(method) = self.methods.get(&message.method) else {
251            return invalid_or_dropped!(message.message_type(), ReturnCode::UnknownMethod);
252        };
253
254        // Check if the message type is correct.
255        match direction {
256            Direction::Incoming => match (self.flavor, method) {
257                (InterfaceType::Stub, MethodType::Procedure) => {
258                    if message.message_type() != MessageType::RequestNoReturn {
259                        return drop!(ReturnCode::WrongMessageType);
260                    }
261                }
262                (InterfaceType::Stub, MethodType::Method) => {
263                    if message.message_type() != MessageType::Request {
264                        return invalid!(ReturnCode::WrongMessageType);
265                    }
266                }
267                (InterfaceType::Proxy, MethodType::Method) => {
268                    if !matches!(
269                        message.message_type(),
270                        MessageType::Response | MessageType::Error
271                    ) {
272                        return drop!(ReturnCode::WrongMessageType);
273                    }
274                }
275                (InterfaceType::Proxy, MethodType::Event) => {
276                    if message.message_type() != MessageType::Notification {
277                        return drop!(ReturnCode::WrongMessageType);
278                    }
279                }
280                _ => return drop!(ReturnCode::WrongMessageType),
281            },
282            Direction::Outgoing => match (self.flavor, method) {
283                (InterfaceType::Stub, MethodType::Method) => {
284                    if !matches!(
285                        message.message_type(),
286                        MessageType::Response | MessageType::Error
287                    ) {
288                        return invalid!(ReturnCode::WrongMessageType);
289                    }
290                }
291                (InterfaceType::Stub, MethodType::Event) => {
292                    if message.message_type() != MessageType::Notification {
293                        return invalid!(ReturnCode::WrongMessageType);
294                    }
295                }
296                (InterfaceType::Proxy, MethodType::Procedure) => {
297                    if message.message_type() != MessageType::RequestNoReturn {
298                        return invalid!(ReturnCode::WrongMessageType);
299                    }
300                }
301                (InterfaceType::Proxy, MethodType::Method) => {
302                    if message.message_type() != MessageType::Request {
303                        return invalid!(ReturnCode::WrongMessageType);
304                    }
305                }
306                _ => return invalid!(ReturnCode::WrongMessageType),
307            },
308        }
309        Ok(())
310    }
311}
312
313/// The type of a SOME/IP service interface.
314///
315/// This defines how it should process SOME/IP messages.
316#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
317pub enum InterfaceType {
318    /// A service interface being served on a local endpoint.
319    #[default]
320    Stub,
321    /// A service interface being served on a remote endpoint.
322    Proxy,
323}
324
325/// The type of a SOME/IP method.
326///
327/// This defines how it should process SOME/IP messages.
328#[derive(Debug, Clone, Copy, PartialEq, Eq)]
329pub enum MethodType {
330    /// A callable function on a service interface that does not return a value.
331    Procedure,
332    /// A callable function on a service interface that returns a value.
333    Method,
334    /// A non-callable event on the service interface.
335    Event,
336}
337
338/// The direction an event is taking through the endpoint.
339#[derive(Debug, Clone, Copy, PartialEq, Eq)]
340pub enum Direction {
341    /// The event is coming from a remote endpoint.
342    Incoming,
343    /// The event is going to a remote endpoint.
344    Outgoing,
345}
346
347/// A message processing error.
348///
349/// A SOME/IP endpoint may occasionally try to send or receive messages which are incorrectly
350/// configured for the service interface that processes them.
351///
352/// This enum serves as a way to represent the reason for a message to not be processed, as well as
353/// whether the error should be reported to the user or not.
354///
355/// # Error Handling
356///
357/// Depending on the error variant, either an error response should be sent back to the source or the
358/// whole message should be dropped.
359///
360/// If the error is [`MessageError::Invalid`], then an error response should be sent with the
361/// contained [`ReturnCode`]. Otherwise, the message should be dropped.
362#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
363pub enum MessageError {
364    #[error("invalid message: {0}")]
365    Invalid(ReturnCode),
366    #[error("message dropped: {0}")]
367    Dropped(ReturnCode),
368}
369
370impl MessageError {
371    /// Creates a new [`MessageError::Invalid`] or [`MessageError::Dropped`] depending on the
372    /// [`MessageType`].
373    ///
374    /// This is used to reduce the verbosity of having to specify whether a message should be
375    /// responded to or dropped in case of an error.
376    fn invalid_or_dropped(message_type: MessageType, return_code: ReturnCode) -> Self {
377        if message_type == MessageType::Request {
378            Self::Invalid(return_code)
379        } else {
380            Self::Dropped(return_code)
381        }
382    }
383}
384
385#[cfg(test)]
386mod tests {
387    use super::*;
388
389    /// A SOME/IP message.
390    type Message = crate::Message<rsomeip_bytes::Bytes>;
391
392    #[test]
393    fn interface_version_is_checked() {
394        // Create a new interface with a specific version.
395        let interface = Interface::default().with_version(InterfaceVersion::new(1));
396
397        // Check incoming and outgoing messages.
398        for value in [
399            MessageType::Request,
400            MessageType::Response,
401            MessageType::RequestNoReturn,
402            MessageType::Error,
403            MessageType::Notification,
404            MessageType::Unknown(0xff),
405        ] {
406            // Requests should not be dropped.
407            if value == MessageType::Request {
408                assert_eq!(
409                    interface.check(
410                        &Message::default().with_message_type(value),
411                        Direction::Incoming
412                    ),
413                    invalid!(ReturnCode::WrongInterfaceVersion)
414                );
415                assert_eq!(
416                    interface.check(
417                        &Message::default().with_message_type(value),
418                        Direction::Outgoing
419                    ),
420                    invalid!(ReturnCode::WrongInterfaceVersion)
421                );
422            } else {
423                assert_eq!(
424                    interface.check(
425                        &Message::default().with_message_type(value),
426                        Direction::Incoming
427                    ),
428                    drop!(ReturnCode::WrongInterfaceVersion)
429                );
430                assert_eq!(
431                    interface.check(
432                        &Message::default().with_message_type(value),
433                        Direction::Outgoing
434                    ),
435                    drop!(ReturnCode::WrongInterfaceVersion)
436                );
437            }
438        }
439    }
440
441    #[test]
442    fn method_id_is_checked() {
443        // Create a new interface without any methods.
444        let interface = Interface::default();
445
446        // Check incoming and outgoing messages.
447        for value in [
448            MessageType::Request,
449            MessageType::Response,
450            MessageType::RequestNoReturn,
451            MessageType::Error,
452            MessageType::Notification,
453            MessageType::Unknown(0xff),
454        ] {
455            // Requests should not be dropped.
456            if value == MessageType::Request {
457                assert_eq!(
458                    interface.check(
459                        &Message::default().with_message_type(value),
460                        Direction::Incoming
461                    ),
462                    invalid!(ReturnCode::UnknownMethod)
463                );
464                assert_eq!(
465                    interface.check(
466                        &Message::default().with_message_type(value),
467                        Direction::Outgoing
468                    ),
469                    invalid!(ReturnCode::UnknownMethod)
470                );
471            } else {
472                assert_eq!(
473                    interface.check(
474                        &Message::default().with_message_type(value),
475                        Direction::Incoming
476                    ),
477                    drop!(ReturnCode::UnknownMethod)
478                );
479                assert_eq!(
480                    interface.check(
481                        &Message::default().with_message_type(value),
482                        Direction::Outgoing
483                    ),
484                    drop!(ReturnCode::UnknownMethod)
485                );
486            }
487        }
488    }
489
490    #[test]
491    fn stub_method_valid_message_types() {
492        // Create a service interface stub.
493        let interface = Interface::default().with_method(MethodId::default());
494
495        // Check incoming messages.
496        assert_eq!(
497            interface.check(&Message::default(), Direction::Incoming),
498            Ok(())
499        );
500
501        // Check outgoing messages.
502        for value in [MessageType::Response, MessageType::Error] {
503            assert_eq!(
504                interface.check(
505                    &Message::default().with_message_type(value),
506                    Direction::Outgoing
507                ),
508                Ok(())
509            );
510        }
511    }
512
513    #[test]
514    fn stub_method_invalid_message_types() {
515        // Create a service interface stub.
516        let interface = Interface::default().with_method(MethodId::default());
517
518        // Check incoming messages.
519        for value in [
520            MessageType::Error,
521            MessageType::Notification,
522            MessageType::RequestNoReturn,
523            MessageType::Response,
524            MessageType::Unknown(0xff),
525        ] {
526            assert_eq!(
527                interface.check(
528                    &Message::default().with_message_type(value),
529                    Direction::Incoming
530                ),
531                invalid!(ReturnCode::WrongMessageType)
532            );
533        }
534
535        // Check outgoing messages.
536        for value in [
537            MessageType::Request,
538            MessageType::Notification,
539            MessageType::RequestNoReturn,
540            MessageType::Unknown(0xff),
541        ] {
542            assert_eq!(
543                interface.check(
544                    &Message::default().with_message_type(value),
545                    Direction::Outgoing
546                ),
547                invalid!(ReturnCode::WrongMessageType)
548            );
549        }
550    }
551
552    #[test]
553    fn stub_procedure_valid_message_types() {
554        // Create a service interface stub.
555        let interface = Interface::default().with_procedure(MethodId::default());
556
557        // Check incoming messages.
558        assert_eq!(
559            interface.check(
560                &Message::default().with_message_type(MessageType::RequestNoReturn),
561                Direction::Incoming
562            ),
563            Ok(())
564        );
565    }
566
567    #[test]
568    fn stub_procedure_invalid_message_types() {
569        // Create a service interface stub.
570        let interface = Interface::default().with_procedure(MethodId::default());
571
572        // Check incoming messages.
573        for value in [
574            MessageType::Error,
575            MessageType::Notification,
576            MessageType::Request,
577            MessageType::Response,
578            MessageType::Unknown(0xff),
579        ] {
580            assert_eq!(
581                interface.check(
582                    &Message::default().with_message_type(value),
583                    Direction::Incoming
584                ),
585                drop!(ReturnCode::WrongMessageType)
586            );
587        }
588
589        // Check outgoing messages.
590        for value in [
591            MessageType::Error,
592            MessageType::Notification,
593            MessageType::Request,
594            MessageType::RequestNoReturn,
595            MessageType::Response,
596            MessageType::Unknown(0xff),
597        ] {
598            assert_eq!(
599                interface.check(
600                    &Message::default().with_message_type(value),
601                    Direction::Outgoing
602                ),
603                invalid!(ReturnCode::WrongMessageType)
604            );
605        }
606    }
607
608    #[test]
609    fn stub_event_valid_message_types() {
610        // Create a service interface stub.
611        let interface = Interface::default().with_event(MethodId::default());
612
613        // Check outgoing messages.
614        assert_eq!(
615            interface.check(
616                &Message::default().with_message_type(MessageType::Notification),
617                Direction::Outgoing
618            ),
619            Ok(())
620        );
621    }
622
623    #[test]
624    fn stub_event_only_handles_notifications() {
625        // Create a service interface stub.
626        let interface = Interface::default().with_event(MethodId::default());
627
628        // Check incoming messages.
629        for value in [
630            MessageType::Error,
631            MessageType::Notification,
632            MessageType::Request,
633            MessageType::RequestNoReturn,
634            MessageType::Response,
635            MessageType::Unknown(0xff),
636        ] {
637            assert_eq!(
638                interface.check(
639                    &Message::default().with_message_type(value),
640                    Direction::Incoming
641                ),
642                drop!(ReturnCode::WrongMessageType)
643            );
644        }
645
646        // Check outgoing messages.
647        for value in [
648            MessageType::Error,
649            MessageType::Request,
650            MessageType::RequestNoReturn,
651            MessageType::Response,
652            MessageType::Unknown(0xff),
653        ] {
654            assert_eq!(
655                interface.check(
656                    &Message::default().with_message_type(value),
657                    Direction::Outgoing
658                ),
659                invalid!(ReturnCode::WrongMessageType)
660            );
661        }
662    }
663
664    #[test]
665    fn proxy_method_valid_message_types() {
666        // Create a service interface proxy.
667        let interface = Interface::default()
668            .with_method(MethodId::default())
669            .into_proxy();
670
671        // Check incoming messages.
672        for value in [MessageType::Response, MessageType::Error] {
673            assert_eq!(
674                interface.check(
675                    &Message::default().with_message_type(value),
676                    Direction::Incoming
677                ),
678                Ok(())
679            );
680        }
681
682        // Check outgoing messages.
683        assert_eq!(
684            interface.check(
685                &Message::default().with_message_type(MessageType::Request),
686                Direction::Outgoing
687            ),
688            Ok(())
689        );
690    }
691
692    #[test]
693    fn proxy_method_invalid_message_types() {
694        // Create a service interface proxy.
695        let interface = Interface::default()
696            .with_method(MethodId::default())
697            .into_proxy();
698
699        // Check incoming messages.
700        for value in [
701            MessageType::Request,
702            MessageType::Notification,
703            MessageType::RequestNoReturn,
704            MessageType::Unknown(0xff),
705        ] {
706            assert_eq!(
707                interface.check(
708                    &Message::default().with_message_type(value),
709                    Direction::Incoming
710                ),
711                drop!(ReturnCode::WrongMessageType)
712            );
713        }
714
715        // Check outgoing messages.
716        for value in [
717            MessageType::Response,
718            MessageType::Error,
719            MessageType::Notification,
720            MessageType::RequestNoReturn,
721            MessageType::Unknown(0xff),
722        ] {
723            assert_eq!(
724                interface.check(
725                    &Message::default().with_message_type(value),
726                    Direction::Outgoing
727                ),
728                invalid!(ReturnCode::WrongMessageType)
729            );
730        }
731    }
732
733    #[test]
734    fn proxy_procedure_valid_message_types() {
735        // Create a service interface proxy.
736        let interface = Interface::default()
737            .with_procedure(MethodId::default())
738            .into_proxy();
739
740        // Check outgoing messages.
741        assert_eq!(
742            interface.check(
743                &Message::default().with_message_type(MessageType::RequestNoReturn),
744                Direction::Outgoing
745            ),
746            Ok(())
747        );
748    }
749
750    #[test]
751    fn proxy_procedure_invalid_message_types() {
752        // Create a service interface proxy.
753        let interface = Interface::default()
754            .with_procedure(MethodId::default())
755            .into_proxy();
756
757        // Check incoming messages.
758        for value in [
759            MessageType::Error,
760            MessageType::Notification,
761            MessageType::Request,
762            MessageType::RequestNoReturn,
763            MessageType::Response,
764            MessageType::Unknown(0xff),
765        ] {
766            assert_eq!(
767                interface.check(
768                    &Message::default().with_message_type(value),
769                    Direction::Incoming
770                ),
771                drop!(ReturnCode::WrongMessageType)
772            );
773        }
774
775        // Check outgoing messages.
776        for value in [
777            MessageType::Error,
778            MessageType::Notification,
779            MessageType::Request,
780            MessageType::Response,
781            MessageType::Unknown(0xff),
782        ] {
783            assert_eq!(
784                interface.check(
785                    &Message::default().with_message_type(value),
786                    Direction::Outgoing
787                ),
788                invalid!(ReturnCode::WrongMessageType)
789            );
790        }
791    }
792
793    #[test]
794    fn proxy_event_valid_message_types() {
795        // Create a service interface proxy.
796        let interface = Interface::default()
797            .with_event(MethodId::default())
798            .into_proxy();
799
800        // Check incoming messages.
801        assert_eq!(
802            interface.check(
803                &Message::default().with_message_type(MessageType::Notification),
804                Direction::Incoming
805            ),
806            Ok(())
807        );
808    }
809
810    #[test]
811    fn proxy_event_invalid_message_types() {
812        // Create a service interface proxy.
813        let interface = Interface::default()
814            .with_event(MethodId::default())
815            .into_proxy();
816
817        // Check incoming messages.
818        for value in [
819            MessageType::Error,
820            MessageType::Request,
821            MessageType::RequestNoReturn,
822            MessageType::Response,
823            MessageType::Unknown(0xff),
824        ] {
825            assert_eq!(
826                interface.check(
827                    &Message::default().with_message_type(value),
828                    Direction::Incoming
829                ),
830                drop!(ReturnCode::WrongMessageType)
831            );
832        }
833
834        // Check outgoing messages.
835        for value in [
836            MessageType::Error,
837            MessageType::Request,
838            MessageType::RequestNoReturn,
839            MessageType::Notification,
840            MessageType::Response,
841            MessageType::Unknown(0xff),
842        ] {
843            assert_eq!(
844                interface.check(
845                    &Message::default().with_message_type(value),
846                    Direction::Outgoing
847                ),
848                invalid!(ReturnCode::WrongMessageType)
849            );
850        }
851    }
852}