Skip to content

Commit b71e92b

Browse files
committed
separated lib.rs into multiple files for better code organization
1 parent 20e1571 commit b71e92b

5 files changed

Lines changed: 234 additions & 219 deletions

File tree

.vscode/settings.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,12 @@
33
"activityBar.background": "#422809",
44
"titleBar.activeBackground": "#5D380D",
55
"titleBar.activeForeground": "#FDF9F3"
6-
}
6+
},
7+
"cSpell.words": [
8+
"Iceoryx",
9+
"mqtt",
10+
"uentity",
11+
"utransport",
12+
"uuri"
13+
]
714
}

src/iceoryx2_transport.rs

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
use up_rust::{UCode, UStatus, UUri};
2+
use crate::message_type::MessageType;
3+
4+
/// This will be the main struct for our uProtocol transport.
5+
/// It will hold the state necessary to communicate with iceoryx2,
6+
/// such as the service connection and active listeners.
7+
pub struct Iceoryx2Transport {}
8+
9+
#[allow(dead_code)]
10+
impl Iceoryx2Transport {
11+
fn encode_uuri_segments(uuri: &UUri) -> Vec<String> {
12+
vec![
13+
uuri.authority_name.clone(),
14+
Self::encode_hex(uuri.uentity_type_id() as u32),
15+
Self::encode_hex(uuri.uentity_instance_id() as u32),
16+
Self::encode_hex(uuri.uentity_major_version() as u32),
17+
Self::encode_hex(uuri.resource_id() as u32),
18+
]
19+
}
20+
21+
fn encode_hex(value: u32) -> String {
22+
format!("{:X}", value)
23+
}
24+
25+
/// Assumption: valid source and sink URIs provided:
26+
/// send() makes use of UAttributesValidator
27+
/// register_listener() and unregister_listener() use verify_filter_criteria()
28+
/// Criteria for identification of message types can be found here: https://github.com/eclipse-uprotocol/up-spec/blob/main/basics/uattributes.adoc
29+
fn determine_message_type(source: &UUri, sink: Option<&UUri>) -> Result<MessageType, UStatus> {
30+
let src_id = source.resource_id;
31+
let sink_id = sink.map(|s| s.resource_id);
32+
33+
if src_id == 0 {
34+
if let Some(id) = sink_id {
35+
if id >= 1 && id <= 0x7FFF {
36+
return Ok(MessageType::RpcRequest);
37+
}
38+
}
39+
} else if sink_id == Some(0) && src_id >= 1 && src_id <= 0xFFFE {
40+
return Ok(MessageType::RpcResponseOrNotification);
41+
} else if src_id >= 1 && src_id <= 0x7FFF {
42+
return Ok(MessageType::Publish);
43+
}
44+
45+
Err(UStatus::fail_with_code(
46+
UCode::INVALID_ARGUMENT,
47+
"Unsupported UMessageType",
48+
))
49+
}
50+
51+
/// Called in send(), register_listener() and unregister_listener()
52+
fn compute_service_name(source: &UUri, sink: Option<&UUri>) -> Result<String, UStatus> {
53+
let join_segments = |segments: Vec<String>| segments.join("/");
54+
55+
match Self::determine_message_type(source, sink)? {
56+
MessageType::RpcRequest => {
57+
let Some(sink_uri) = sink else {
58+
return Err(UStatus::fail_with_code(
59+
UCode::INVALID_ARGUMENT,
60+
"sink required for RpcRequest",
61+
));
62+
};
63+
let segments = Self::encode_uuri_segments(sink_uri);
64+
Ok(format!("up/{}", join_segments(segments)))
65+
}
66+
MessageType::RpcResponseOrNotification => {
67+
let Some(sink_uri) = sink else {
68+
return Err(UStatus::fail_with_code(
69+
UCode::INVALID_ARGUMENT,
70+
"sink required for ResponseOrNotification",
71+
));
72+
};
73+
let source_segments = Self::encode_uuri_segments(source);
74+
let sink_segments = Self::encode_uuri_segments(sink_uri);
75+
Ok(format!(
76+
"up/{}/{}",
77+
join_segments(source_segments),
78+
join_segments(sink_segments)
79+
))
80+
}
81+
MessageType::Publish => {
82+
let segments = Self::encode_uuri_segments(source);
83+
Ok(format!("up/{}", join_segments(segments)))
84+
}
85+
}
86+
}
87+
}
88+
89+
#[cfg(test)]
90+
mod tests {
91+
use super::*;
92+
use up_rust::{UCode, UUri};
93+
94+
fn test_uri(authority: &str, instance: u16, typ: u16, version: u8, resource: u16) -> UUri {
95+
let entity_id = ((instance as u32) << 16) | (typ as u32);
96+
UUri::try_from_parts(authority, entity_id, version, resource).unwrap()
97+
}
98+
99+
// performing successful tests for service name computation
100+
101+
#[test]
102+
// [specitem,oft-sid="dsn~up-transport-iceoryx2-service-name~1",oft-needs="utest"]
103+
fn test_publish_service_name() {
104+
let source = test_uri("device1", 0x0000, 0x10AB, 0x03, 0x7FFF);
105+
106+
let name = Iceoryx2Transport::compute_service_name(&source, None).unwrap();
107+
assert_eq!(name, "up/device1/10AB/0/3/7FFF");
108+
}
109+
110+
#[test]
111+
// [specitem,oft-sid="dsn~up-transport-iceoryx2-service-name~1",oft-needs="utest"]
112+
fn test_notification_service_name() {
113+
let source = test_uri("device1", 0x0000, 0x10AB, 0x03, 0x80CD);
114+
let sink = test_uri("device1", 0x0000, 0x30EF, 0x04, 0x0000);
115+
let name = Iceoryx2Transport::compute_service_name(&source, Some(&sink)).unwrap();
116+
assert_eq!(name, "up/device1/10AB/0/3/80CD/device1/30EF/0/4/0");
117+
}
118+
119+
#[test]
120+
// [specitem,oft-sid="dsn~up-transport-iceoryx2-service-name~1",oft-needs="utest"]
121+
fn test_rpc_request_service_name() {
122+
let sink = test_uri("device1", 0x0004, 0x03AB, 0x03, 0x0000);
123+
let reply_to = test_uri("device1", 0x0000, 0x00CD, 0x04, 0xB);
124+
125+
let name = Iceoryx2Transport::compute_service_name(&sink, Some(&reply_to)).unwrap();
126+
assert_eq!(name, "up/device1/CD/0/4/B");
127+
}
128+
129+
#[test]
130+
// [specitem,oft-sid="dsn~up-transport-iceoryx2-service-name~1",oft-needs="utest"]
131+
fn test_rpc_response_service_name() {
132+
let source = test_uri("device1", 0x0000, 0x00CD, 0x04, 0xB);
133+
let sink = test_uri("device1", 0x0004, 0x3AB, 0x3, 0x0000);
134+
135+
let name = Iceoryx2Transport::compute_service_name(&source, Some(&sink)).unwrap();
136+
assert_eq!(name, "up/device1/CD/0/4/B/device1/3AB/4/3/0");
137+
}
138+
139+
// performing failing tests for service name computation
140+
141+
#[test]
142+
// .specitem[dsn~up-attributes-request-source~1]
143+
// .specitem[dsn~up-attributes-response-source~1]
144+
// .specitem[dsn~up-attributes-notification-source~1]
145+
fn test_missing_uri_error() {
146+
let uuri = UUri::new();
147+
let result = Iceoryx2Transport::compute_service_name(&uuri, None);
148+
149+
assert!(result.is_err());
150+
assert_eq!(result.unwrap_err().get_code(), UCode::INVALID_ARGUMENT);
151+
}
152+
153+
#[test]
154+
//both source and sink have resource ID equal to 0
155+
// .specitem[dsn~up-attributes-request-source~1]
156+
// .specitem[dsn~up-attributes-request-sink~1]
157+
// .specitem[dsn~up-attributes-response-source~1]
158+
// .specitem[dsn~up-attributes-response-sink~1]
159+
fn test_fail_resource_id_error() {
160+
let source = test_uri("device1", 0x0000, 0x00CD, 0x04, 0x000);
161+
let sink = test_uri("device1", 0x0004, 0x3AB, 0x3, 0x0000);
162+
let result = Iceoryx2Transport::compute_service_name(&source, Some(&sink));
163+
assert!(result.is_err_and(|err| err.get_code() == UCode::INVALID_ARGUMENT));
164+
}
165+
166+
#[test]
167+
//source has resource id=0 but missing sink
168+
// .specitem[dsn~up-attributes-request-sink~1]
169+
// .specitem[dsn~up-attributes-request-source~1]
170+
fn test_fail_missing_sink_error() {
171+
let source = test_uri("device1", 0x0000, 0x00CD, 0x04, 0x000);
172+
let result = Iceoryx2Transport::compute_service_name(&source, None);
173+
assert!(result.is_err_and(|err| err.get_code() == UCode::INVALID_ARGUMENT));
174+
}
175+
176+
#[test]
177+
//missing source URI
178+
// .specitem[dsn~up-attributes-request-source~1]
179+
// .specitem[dsn~up-attributes-response-source~1]
180+
// .specitem[dsn~up-attributes-notification-source~1]
181+
fn test_fail_missing_source_error() {
182+
let uuri = UUri::new();
183+
let sink = test_uri("device1", 0x0004, 0x3AB, 0x3, 0x000);
184+
let result = Iceoryx2Transport::compute_service_name(&uuri, Some(&sink));
185+
assert!(result.is_err_and(|err| err.get_code() == UCode::INVALID_ARGUMENT));
186+
}
187+
}

0 commit comments

Comments
 (0)