Preview of the proposed up-rust native-frame-model branch (up-rust b6b99c6d, up-spec f0e9b17) — not released documentation. branch · write-up

up_rust/uattributes/
umessagetype.rs

1/********************************************************************************
2 * Copyright (c) 2023 Contributors to the Eclipse Foundation
3 *
4 * See the NOTICE file(s) distributed with this work for additional
5 * information regarding copyright ownership.
6 *
7 * This program and the accompanying materials are made available under the
8 * terms of the Apache License Version 2.0 which is available at
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * SPDX-License-Identifier: Apache-2.0
12 ********************************************************************************/
13
14use crate::uattributes::UAttributesError;
15
16const CE_TYPE_PUBLISH: &str = "up-pub.v1";
17const CE_TYPE_NOTIFICATION: &str = "up-not.v1";
18const CE_TYPE_REQUEST: &str = "up-req.v1";
19const CE_TYPE_RESPONSE: &str = "up-res.v1";
20
21#[derive(Debug, Clone, Copy, PartialEq)]
22#[repr(C)]
23/// The four uProtocol message kinds.
24pub enum UMessageType {
25    /// A publication to a topic; delivered to all subscribers.
26    Publish,
27    /// An RPC request targeting a method.
28    Request,
29    /// An RPC response correlated to a request.
30    Response,
31    /// A notification targeting one uEntity.
32    Notification,
33}
34
35impl UMessageType {
36    /// Gets this message type's CloudEvent type name.
37    ///
38    /// # Returns
39    ///
40    /// The value to use for the *type* property when mapping to a CloudEvent.
41    #[must_use]
42    pub fn to_cloudevent_type(&self) -> String {
43        match self {
44            UMessageType::Publish => CE_TYPE_PUBLISH,
45            UMessageType::Request => CE_TYPE_REQUEST,
46            UMessageType::Response => CE_TYPE_RESPONSE,
47            UMessageType::Notification => CE_TYPE_NOTIFICATION,
48        }
49        .to_string()
50    }
51
52    /// Gets the message type for a CloudEvent type name.
53    ///
54    /// # Errors
55    ///
56    /// Returns a [`UAttributesError::ParsingError`] if the given name does not match
57    /// any of the supported message types.
58    pub fn try_from_cloudevent_type<S: Into<String>>(value: S) -> Result<Self, UAttributesError> {
59        let type_string = value.into();
60        match type_string.as_str() {
61            CE_TYPE_PUBLISH => Ok(UMessageType::Publish),
62            CE_TYPE_NOTIFICATION => Ok(UMessageType::Notification),
63            CE_TYPE_REQUEST => Ok(UMessageType::Request),
64            CE_TYPE_RESPONSE => Ok(UMessageType::Response),
65            _ => Err(UAttributesError::parsing_error(format!(
66                "unknown message type: {type_string}"
67            ))),
68        }
69    }
70}
71
72#[cfg(feature = "up-core-api")]
73mod core_types_support {
74    use super::*;
75    use crate::up_core_api::uattributes::UMessageType as UMessageTypeProto;
76
77    impl TryFrom<UMessageTypeProto> for UMessageType {
78        type Error = UAttributesError;
79
80        fn try_from(proto_message_type: UMessageTypeProto) -> Result<Self, Self::Error> {
81            match proto_message_type {
82                UMessageTypeProto::UMESSAGE_TYPE_PUBLISH => Ok(UMessageType::Publish),
83                UMessageTypeProto::UMESSAGE_TYPE_REQUEST => Ok(UMessageType::Request),
84                UMessageTypeProto::UMESSAGE_TYPE_RESPONSE => Ok(UMessageType::Response),
85                UMessageTypeProto::UMESSAGE_TYPE_NOTIFICATION => Ok(UMessageType::Notification),
86                _ => Err(UAttributesError::parsing_error(format!(
87                    "invalid UMessageType value: {}",
88                    proto_message_type as i32
89                ))),
90            }
91        }
92    }
93
94    impl From<&UMessageType> for UMessageTypeProto {
95        fn from(value: &UMessageType) -> Self {
96            match value {
97                UMessageType::Publish => UMessageTypeProto::UMESSAGE_TYPE_PUBLISH,
98                UMessageType::Request => UMessageTypeProto::UMESSAGE_TYPE_REQUEST,
99                UMessageType::Response => UMessageTypeProto::UMESSAGE_TYPE_RESPONSE,
100                UMessageType::Notification => UMessageTypeProto::UMESSAGE_TYPE_NOTIFICATION,
101            }
102        }
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use test_case::test_case;
109
110    use crate::{UAttributesError, UMessageType};
111
112    const TYPE_PUBLISH: &str = "up-pub.v1";
113    const TYPE_NOTIFICATION: &str = "up-not.v1";
114    const TYPE_REQUEST: &str = "up-req.v1";
115    const TYPE_RESPONSE: &str = "up-res.v1";
116
117    #[test_case(UMessageType::Publish, TYPE_PUBLISH; "for PUBLISH")]
118    #[test_case(UMessageType::Notification, TYPE_NOTIFICATION; "for NOTIFICATION")]
119    #[test_case(UMessageType::Request, TYPE_REQUEST; "for REQUEST")]
120    #[test_case(UMessageType::Response, TYPE_RESPONSE; "for RESPONSE")]
121    fn test_to_cloudevent_type(message_type: UMessageType, expected_ce_name: &str) {
122        assert_eq!(message_type.to_cloudevent_type(), expected_ce_name);
123    }
124
125    #[test_case(TYPE_PUBLISH, Some(UMessageType::Publish); "succeeds for PUBLISH")]
126    #[test_case(TYPE_NOTIFICATION, Some(UMessageType::Notification); "succeeds for NOTIFICATION")]
127    #[test_case(TYPE_REQUEST, Some(UMessageType::Request); "succeeds for REQUEST")]
128    #[test_case(TYPE_RESPONSE, Some(UMessageType::Response); "succeeds for RESPONSE")]
129    #[test_case("foo.bar", None; "fails for unknown type")]
130    fn test_try_from_cloudevent_type(
131        cloudevent_type: &str,
132        expected_message_type: Option<UMessageType>,
133    ) {
134        let result = UMessageType::try_from_cloudevent_type(cloudevent_type);
135        assert!(result.is_ok() == expected_message_type.is_some());
136        if let Some(message_type) = expected_message_type {
137            assert_eq!(result.unwrap(), message_type)
138        } else {
139            assert!(matches!(
140                result.unwrap_err(),
141                UAttributesError::ParsingError(_msg)
142            ))
143        }
144    }
145}