diff --git a/crates/rmw/Cargo.toml b/crates/rmw/Cargo.toml deleted file mode 100644 index a940e49..0000000 --- a/crates/rmw/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "rmw" -version = "0.1.0" -edition = "2021" - -[dependencies] -log = "0.4.14" -r2utils = { path = "../r2utils" } -r2idl = { path = "../r2idl" } diff --git a/crates/rmw/LICENSE b/crates/rmw/LICENSE deleted file mode 100644 index 137069b..0000000 --- a/crates/rmw/LICENSE +++ /dev/null @@ -1,73 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/crates/rmw/README.md b/crates/rmw/README.md deleted file mode 100644 index 077a34a..0000000 --- a/crates/rmw/README.md +++ /dev/null @@ -1,3 +0,0 @@ - -# RMW -R2 Middleware is the abstract layer to DDS-like message services. diff --git a/crates/rmw/src/domain_id.rs b/crates/rmw/src/domain_id.rs deleted file mode 100644 index c059de0..0000000 --- a/crates/rmw/src/domain_id.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -/// Type alias for `DomainId`. -pub type DomainId = usize; - -/// Default domain id, used in init options. -pub const DEFAULT_DOMAIN_ID: DomainId = usize::MAX; diff --git a/crates/rmw/src/event.rs b/crates/rmw/src/event.rs deleted file mode 100644 index 6fc539c..0000000 --- a/crates/rmw/src/event.rs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use crate::ret_types::RetType; -use crate::types::{PublisherTrait, Subscription}; - -/// Define publisher/subscription events -#[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum EventType { - /// Subscription events - LivelinessChanged, - RequestedDeadlineMissed, - RequestedQoSIncompatible, - MessageLost, - - /// publisher events - LivelinessLost, - OfferedDeadlineMissed, - OfferedQoSIncompatible, - - /// sentinel value - Invalid, -} - -/// Encapsulate the RMW event implementation, data, and type. -pub trait EventBaseTrait: Clone { - /// Implementation identifier, used to ensure two different implementations are not being mixed. - fn implementation_identifier(&self) -> &'static str; - - /// Data specific to this event type from either the publisher or subscriber. - fn data(&self) -> &[u8]; - - /// The event type that occurred. - fn event_type(&self) -> EventType; - - /// Return a zero initialized event structure. - fn zero_initialized() -> Self; -} - -/// Initialize a rmw subscription event. -pub trait EventTrait: EventBaseTrait { - /// Initialize a rmw publisher event. - fn publisher_event_init( - &mut self, - publisher: &dyn PublisherTrait, - event_type: EventType, - ) -> RetType; - - /// Initialize a rmw subscription event. - fn subscription_event_init( - &mut self, - subscription: &Subscription, - event_type: EventType, - ) -> RetType; - - /// Take an event from the event handle. - fn take_event(&mut self, event_info: &mut usize, taken: &mut bool) -> RetType; -} - -#[derive(Debug)] -pub struct Events(Vec); diff --git a/crates/rmw/src/events_statuses/incompatible_qos.rs b/crates/rmw/src/events_statuses/incompatible_qos.rs deleted file mode 100644 index e4eb19e..0000000 --- a/crates/rmw/src/events_statuses/incompatible_qos.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use crate::qos_policy_kind::QoSPolicyKind; - -#[derive(Debug)] -pub struct QoSIncompatibleEventStatus { - /// Total cumulative number of times the concerned subscription discovered a - /// publisher for the same topic with an offered QoS that was incompatible - /// with that requested by the subscription. - pub total_count: i32, - - /// The change in total_count since the last time the status was read. - pub total_count_change: i32, - - /// The Qos Policy Kind of one of the policies that was found to be - /// incompatible the last time an incompatibility was detected. - pub last_policy_kind: QoSPolicyKind, -} - -/// Event state for a subscription's 'RMW_EVENT_REQUESTED_QOS_INCOMPATIBLE' events. -pub type RequestedQosIncompatibleEventStatus = QoSIncompatibleEventStatus; - -/// Event state for a publisher's 'RMW_EVENT_OFFERED_QOS_INCOMPATIBLE' events. -pub type OfferedQosIncompatibleEventStatus = QoSIncompatibleEventStatus; diff --git a/crates/rmw/src/events_statuses/liveliness_changed.rs b/crates/rmw/src/events_statuses/liveliness_changed.rs deleted file mode 100644 index 3187700..0000000 --- a/crates/rmw/src/events_statuses/liveliness_changed.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -/// QoS Liveliness Changed information provided by a subscription. -#[derive(Debug)] -pub struct LivelinessChangedStatus { - /// The total number of currently active Publishers which publish to the topic associated with - /// the Subscription. - /// This count increases when a newly matched Publisher asserts its liveliness for the first time - /// or when a Publisher previously considered to be not alive reasserts its liveliness. - /// The count decreases when a Publisher considered alive fails to assert its liveliness and - /// becomes not alive, whether because it was deleted normally or for some other reason. - /// - pub alive_count: i32, - - /// The total count of current Publishers which publish to the topic associated with the - /// Subscription that are no longer asserting their liveliness. - /// This count increases when a Publisher considered alive fails to assert its liveliness and - /// becomes not alive for some reason other than the normal deletion of that Publisher. - /// It decreases when a previously not alive Publisher either reasserts its liveliness or is - /// deleted normally. - pub not_alive_count: i32, - - /// The change in the alive_count since the status was last read. - pub alive_count_change: i32, - - /// The change in the not_alive_count since the status was last read. - pub not_alive_count_change: i32, -} diff --git a/crates/rmw/src/events_statuses/liveliness_lost.rs b/crates/rmw/src/events_statuses/liveliness_lost.rs deleted file mode 100644 index dd033d9..0000000 --- a/crates/rmw/src/events_statuses/liveliness_lost.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -/// QoS Liveliness Lost information provided by a publisher. -#[derive(Debug)] -pub struct LivelinessLostStatus { - /// Lifetime cumulative number of times that a previously-alive Publisher became not alive due to - /// a failure to actively signal its liveliness within its offered liveliness period. - /// This count does not change when an already not alive Publisher simply remains not alive for - /// another liveliness period. - pub total_count: i32, - - /// The change in total_count since the last time the status was last read. - pub total_count_change: i32, -} diff --git a/crates/rmw/src/events_statuses/message_lost.rs b/crates/rmw/src/events_statuses/message_lost.rs deleted file mode 100644 index 83e1196..0000000 --- a/crates/rmw/src/events_statuses/message_lost.rs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -#[derive(Debug)] -pub struct MessageLostStatus { - /// Total number of messages lost. - pub total_count: usize, - - /// Number of messages lost since last callback. - pub total_count_change: usize, -} diff --git a/crates/rmw/src/events_statuses/mod.rs b/crates/rmw/src/events_statuses/mod.rs deleted file mode 100644 index d5bdb60..0000000 --- a/crates/rmw/src/events_statuses/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -pub mod incompatible_qos; -pub mod liveliness_changed; -pub mod liveliness_lost; -pub mod message_lost; -pub mod offered_deadline_missed; -pub mod requested_deadline_missed; diff --git a/crates/rmw/src/events_statuses/offered_deadline_missed.rs b/crates/rmw/src/events_statuses/offered_deadline_missed.rs deleted file mode 100644 index ecf9489..0000000 --- a/crates/rmw/src/events_statuses/offered_deadline_missed.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -/// QoS Deadline Missed information provided by a publisher. -#[derive(Debug)] -pub struct OfferedDeadlineMissedStatus { - /// Lifetime cumulative number of offered deadline periods elapsed during which a Publisher failed - /// to provide data. - /// Missed deadlines accumulate; that is, each deadline period the total_count will be incremented - /// by one. - pub total_count: i32, - - /// The change in total_count since the last time the status was last read. - pub total_count_change: i32, -} diff --git a/crates/rmw/src/events_statuses/requested_deadline_missed.rs b/crates/rmw/src/events_statuses/requested_deadline_missed.rs deleted file mode 100644 index ecf976b..0000000 --- a/crates/rmw/src/events_statuses/requested_deadline_missed.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -/// QoS Requested Deadline Missed information provided by a subscription. -#[derive(Debug)] -pub struct RequestedDeadlineMissedStatus { - /// Lifetime cumulative number of missed deadlines detected for any instance read by the - /// subscription. - /// Missed deadlines accumulate; that is, each deadline period the total_count will be incremented - /// by one for each instance for which data was not received. - pub total_count: i32, - - /// The incremental number of deadlines detected since the status was read. - pub total_count_change: i32, -} diff --git a/crates/rmw/src/init.rs b/crates/rmw/src/init.rs deleted file mode 100644 index 4535f93..0000000 --- a/crates/rmw/src/init.rs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use std::fmt; - -use crate::domain_id::{self, DomainId}; -use crate::init_options::InitOptionsTrait; -use crate::ret_types::{self, RetType}; -use crate::types::{GuardCondition, NodeTrait, WaitSet}; - -/// Initialization context structure which is used to store init specific information. -pub trait ContextBaseTrait { - /// Locally (process local) unique ID that represents this init/shutdown cycle. - fn instance_id(&self) -> u64; - - /// Implementation identifier, used to ensure two different implementations are not being mixed. - fn implementation_identifier(&self) -> &str; - - /// Options used to initialize the context. - fn options(&self) -> &dyn InitOptionsTrait; - - /// Domain id that is being used. - fn actual_domain_id(&self) -> DomainId; - - /// Return a zero initialized context structure. - fn zero_initialized() -> Self; -} - -pub trait ContextTrait: ContextBaseTrait { - /// Initialize the middleware with the given options, and yielding an context. - /// - /// Context is filled with middleware specific data upon success of this function. - /// The context is used when initializing some entities like nodes and - /// guard conditions, and is also required to properly call [`Self::shutdown()`]. - /// - /// The given options must have been initialized - /// i.e. [`init()`] called on it and an enclave set. - /// - /// The given context must be zero initialized. - /// If initialization fails, context will remain zero initialized. - /// - /// [`actual_domain_id`] will be set with the domain id the rmw implementation is using. - /// - /// This matches [`options.domain_id`] if it is not [`domain_id::DEFAULT_DOMAIN_ID`]. - /// In other case, the value is rmw implementation dependent. - /// - /// If options are zero-initialized, then [`ret_types::RET_INVALID_ARGUMENT`] is returned. - /// - /// If options are initialized but no enclave is provided, then [`ret_types::RET_INVALID_ARGUMENT`] is returned. - /// - /// If context has been already initialized ([`Self::init()`] was called on it), then - /// [`ret_types::RET_INVALID_ARGUMENT`] is returned. - /// - /// [`init()`]: InitOptionsTrait#tymethod.init - /// [`actual_domain_id`]: ContextBaseTrait#tymethod.actual_domain_id - /// [`options.domain_id`]: InitOptionsTrait#tymethod.domain_id - fn init(&mut self, options: dyn InitOptionsTrait) -> RetType; - - /// Shutdown the middleware for a given context. - /// - /// The given context must be a valid context which has been initialized with [`Self::init()`]. - /// - /// If context is zero initialized, then [`ret_types::RET_INVALID_ARGUMENT`] is returned. - /// If context has been already invalidated ([`Self::shutdown()`] was called on it), then - /// this function is a no-op and [`ret_types::RET_OK`] is returned. - fn shutdown(&mut self) -> RetType; - - /// Create a node and return a handle to that node. - /// - /// This function can fail, and therefore return `Error`, if: - /// - name is not a valid node name - /// - namespace is not a valid namespace - /// - context is not valid i.e. it is zero-initialized, or - /// its implementation identifier does not match that of - /// this API implementation, or has been invalidated by [`Self::shutdown()`] - /// - memory allocation fails during node creation - /// - an unspecified error occurs - /// - /// Return node handle, or `Error` if there was an error. - fn create_node(&mut self, name: &str, namespace: &str) -> Result; - - /// Create a guard condition and return a handle to that guard condition. - fn create_guard_condition(&mut self) -> GuardCondition; - - /// Create a wait set to store conditions that the middleware can wait on. - fn create_wait_set(&mut self, max_conditions: usize) -> Option; -} diff --git a/crates/rmw/src/init_options.rs b/crates/rmw/src/init_options.rs deleted file mode 100644 index 4e38e2c..0000000 --- a/crates/rmw/src/init_options.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use std::fmt; - -use crate::domain_id::{DomainId, DEFAULT_DOMAIN_ID}; -use crate::init::ContextTrait; -use crate::localhost::LocalhostOnly; -use crate::ret_types::{self, RetType}; -use crate::security_options::SecurityOptions; - -/// Options structure used during [`ContextTrait::init()`]. -pub trait InitOptionsBaseTrait { - /// Locally (process local) unique ID that represents this init/shutdown cycle. - /// - /// This should be set by the caller of [`ContextTrait::init()`] to a number that is - /// unique within this process. - /// - /// It is designed to be used with [`ContextTrait::init()`] and `rcl_get_instance_id()`. - fn instance_id(&self) -> u64; - - /// Implementation identifier, used to ensure two different implementations are not being mixed. - fn implementation_identifier(&self) -> &'static str; - - /// R2 domain id - fn domain_id(&self) -> DomainId; - - /// Security options - fn security_options(&self) -> &SecurityOptions; - - /// Enable localhost only - fn localhost_only(&self) -> LocalhostOnly; - - /// Enclave, name used to find security artifacts in a sr2 keystore. - fn enclave(&self) -> &str; - - /// Return a zero initialized init options structure. - fn zero_initialized() -> Self; -} - -pub trait InitOptionsTrait: InitOptionsBaseTrait { - /// Initialize given init options with the default values and implementation specific values. - /// - /// The given init options must be zero initialized. - /// If initialization fails, init options will remain zero initialized. - /// Giving an already initialized init options will result in a failure - /// with return code [`ret_types::RET_INVALID_ARGUMENT`]. - fn init(&mut self) -> RetType; - - /// Copy the given source init options to the destination init options. - fn copy(self: &Self, dest: &mut Self) -> RetType; -} diff --git a/crates/rmw/src/lib.rs b/crates/rmw/src/lib.rs deleted file mode 100644 index 5d1f506..0000000 --- a/crates/rmw/src/lib.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -pub mod domain_id; -pub mod event; -pub mod events_statuses; -pub mod init; -pub mod init_options; -pub mod localhost; -pub mod message_sequence; -pub mod names_and_types; -pub mod network_flow_endpoint; -pub mod network_flow_endpoint_array; -pub mod qos_policy_kind; -pub mod qos_profiles; -pub mod ret_types; -pub mod rmw; -pub mod security_options; -pub mod serialized_message; -pub mod time; -pub mod topic_endpoint_info; -pub mod topic_endpoint_info_array; -pub mod types; -pub mod validate_namespace; -pub mod validate_node_name; -pub mod validate_topic_name; diff --git a/crates/rmw/src/localhost.rs b/crates/rmw/src/localhost.rs deleted file mode 100644 index 77ea272..0000000 --- a/crates/rmw/src/localhost.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -/// Used to specify if the context can only communicate through localhost. -#[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum LocalhostOnly { - /// Uses `R2_LOCALHOST_ONLY` environment variable. - UseDefault = 0, - - /// Forces using only localhost. - Enabled = 1, - - /// Forces disabling localhost only. - Disabled = 2, -} diff --git a/crates/rmw/src/message_sequence.rs b/crates/rmw/src/message_sequence.rs deleted file mode 100644 index fcc7cbf..0000000 --- a/crates/rmw/src/message_sequence.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use super::types::MessageInfo; - -/// Structure to hold a sequence of R2 messages. -#[derive(Debug, Default)] -pub struct MessageSequence { - /// Array of pointers to R2 messages. - //void ** data; - pub data: Vec, - // The number of valid entries in `data`. - //pub size: usize, - - // The total allocated capacity of the data array. - //pub capacity: usize, -} - -impl MessageSequence { - /// Return a MessageSequence struct with members initialized to `NULL` - pub fn zero_initialized() -> Self { - Self::default() - } -} - -/// Structure to hold a sequence of message infos. -#[derive(Debug, Default)] -pub struct MessageInfoSequence { - /// Array of message info. - pub data: Vec, - // The number of valid entries in data. - //pub size: usize, - // The total allocated capacity of the data array. - //pub capacity: usize, -} - -impl MessageInfoSequence { - /// Return a MessageInfoSequence struct with members initialized to `NULL` - pub fn zero_initialized() -> Self { - Self::default() - } -} diff --git a/crates/rmw/src/names_and_types.rs b/crates/rmw/src/names_and_types.rs deleted file mode 100644 index 20cde7b..0000000 --- a/crates/rmw/src/names_and_types.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use crate::ret_types; - -/// Associative array of topic or service names and types. -#[derive(Debug, Default)] -pub struct NamesAndTypes { - /// Array of names - pub names: Vec, - - /// Dynamic array of arrays of type names, with the same length as `names` - // string_array_t * types; - // TODO(Shaohua): Update type - pub types: Vec, -} - -impl NamesAndTypes { - /// Return a zero initialized array of names and types. - pub fn zero_initialized() -> Self { - Self::default() - } - - /// Check that the given `names_and_types` array is zero initialized. - pub fn check_zero(&self) -> ret_types::RetType { - if !self.names.is_empty() { - log::error!("names array is not zeroed"); - return ret_types::RET_INVALID_ARGUMENT; - } - if !self.types.is_empty() { - log::error!("types array is not NULL"); - return ret_types::RET_INVALID_ARGUMENT; - } - ret_types::RET_OK - } - - /// Initialize an array of names and types. - /// - /// This function initializes the string array for the names and allocates space - /// for all the string arrays for the types according to the given size, but - /// it does not initialize the string array for each setup of types. - /// However, the string arrays for each set of types is zero initialized. - pub fn init(&mut self, size: usize) -> ret_types::RetType { - self.names.resize_with(size, Default::default); - self.types.resize_with(size, Default::default); - ret_types::RET_OK - } -} diff --git a/crates/rmw/src/network_flow_endpoint.rs b/crates/rmw/src/network_flow_endpoint.rs deleted file mode 100644 index b5d6281..0000000 --- a/crates/rmw/src/network_flow_endpoint.rs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use std::fmt; - -use crate::ret_types; - -const UNKNOWN: &str = "Unknown"; - -/// Transport protocol types -#[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum TransportProtocol { - Unknown = 0, - Udp, - Tcp, - Count, -} - -impl fmt::Display for TransportProtocol { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - Self::Unknown => UNKNOWN, - Self::Udp => "UDP", - Self::Tcp => "TCP", - Self::Count => UNKNOWN, - }; - write!(f, "{}", s) - } -} - -/// Internet protocol types -#[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum InternetProtocol { - Unknown = 0, - Ipv4, - Ipv6, - Count, -} - -impl fmt::Display for InternetProtocol { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - Self::Unknown => UNKNOWN, - Self::Ipv4 => "IPv4", - Self::Ipv6 => "IPv6", - Self::Count => UNKNOWN, - }; - write!(f, "{}", s) - } -} - -/// Maximum length of internet address string including terminating null. -/// -/// Inspired from linux/inet.h -pub const INET_ADDRSTRLEN: usize = 48; - -/// Structure that describes network flow endpoint of a publisher or subscription. -#[derive(Debug, Clone, PartialEq)] -pub struct NetworkFlowEndpoint { - /// Transport protocol - pub transport_protocol: TransportProtocol, - - /// Internet protocol - pub internet_protocol: InternetProtocol, - - /// Port - pub transport_port: u16, - - /// Flow label - pub flow_label: u32, - - /// DSCP (Diff. Services Code Point) - pub dscp: u8, - - /// Internet address - pub internet_address: [u8; INET_ADDRSTRLEN], -} - -impl NetworkFlowEndpoint { - /// Return a NetworkFlowEndpoint struct with zero-initialized members. - pub fn zero_inialized() -> Self { - Self::default() - } - - /// Set internet address. - /// - /// Returns `RET_OK` on successfull initilization, - /// or returns `RET_INVALID_ARGUMENT` if `network_flow_endpoint` is NULL, - /// or returns `RET_INVALID_ARGUMENT` if `internet_address` is NULL, - /// or returns `RET_INVALID_ARGUMENT` if size of `internet_address` is - /// more than `INET_ADDRSTRLEN`, or returns `RET_ERROR` when an unspecified error occurs. - pub fn set_internet_address(&mut self, internet_address: &[u8]) -> ret_types::RetType { - if internet_address.len() > INET_ADDRSTRLEN { - log::error!("Size is not less than INET_ADDRSTRLEN"); - return ret_types::RET_INVALID_ARGUMENT; - } - self.internet_address.fill(0); - self.internet_address[0..internet_address.len()].copy_from_slice(internet_address); - ret_types::RET_OK - } -} - -impl Default for NetworkFlowEndpoint { - fn default() -> Self { - Self { - transport_protocol: TransportProtocol::Unknown, - internet_protocol: InternetProtocol::Unknown, - transport_port: 0, - flow_label: 0, - dscp: 0, - internet_address: [0; INET_ADDRSTRLEN], - } - } -} diff --git a/crates/rmw/src/network_flow_endpoint_array.rs b/crates/rmw/src/network_flow_endpoint_array.rs deleted file mode 100644 index 54b101f..0000000 --- a/crates/rmw/src/network_flow_endpoint_array.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use crate::network_flow_endpoint::NetworkFlowEndpoint; - -/// Structure to hold an arrary of NetworkFlowEndpoint. -#[derive(Debug, Default)] -pub struct NetworkFlowEndpointArray(Vec); diff --git a/crates/rmw/src/qos_policy_kind.rs b/crates/rmw/src/qos_policy_kind.rs deleted file mode 100644 index d356ad1..0000000 --- a/crates/rmw/src/qos_policy_kind.rs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use std::fmt; - -const DURABILITY: &str = "durability"; -const DEADLINE: &str = "deadline"; -const LIVELINESS: &str = "liveliness"; -const RELIABILITY: &str = "reliability"; -const HISTORY: &str = "history"; -const LIFESPAN: &str = "lifespan"; -const DEPTH: &str = "depth"; -const LIVELINESS_LEASE_DURATION: &str = "liveliness_lease_duration"; -const AVOID_R2_NAMESPACE_CONVENTIONS: &str = "avoid_r2_namespace_conventions"; - -/// QOS policy kind. -#[repr(u8)] -#[derive(Debug, Clone, Copy, Hash, PartialEq)] -pub enum QoSPolicyKind { - //Invalid = 0, - Durability = 1, - Deadline, - Liveliness, - Reliability, - History, - Lifespan, - Depth, - LivelinessLeaseDuration, - AvoidR2NamespaceConventions, -} - -/// Return a string representing the policy kind. -impl fmt::Display for QoSPolicyKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - Self::Durability => DURABILITY, - Self::Deadline => DEADLINE, - Self::Liveliness => LIVELINESS, - Self::Reliability => RELIABILITY, - Self::History => HISTORY, - Self::Lifespan => LIFESPAN, - Self::Depth => DEPTH, - Self::LivelinessLeaseDuration => LIVELINESS_LEASE_DURATION, - Self::AvoidR2NamespaceConventions => AVOID_R2_NAMESPACE_CONVENTIONS, - }; - write!(f, "{}", s) - } -} - -pub struct ParseQoSPlicyKindError { - pub reason: String, -} - -impl std::str::FromStr for QoSPolicyKind { - type Err = ParseQoSPlicyKindError; - fn from_str(s: &str) -> Result { - if s == DURABILITY { - return Ok(Self::Durability); - } - if s == DEADLINE { - return Ok(Self::Deadline); - } - if s == LIVELINESS { - return Ok(Self::Liveliness); - } - if s == RELIABILITY { - return Ok(Self::Reliability); - } - if s == HISTORY { - return Ok(Self::History); - } - if s == LIFESPAN { - return Ok(Self::Lifespan); - } - if s == DEPTH { - return Ok(Self::Depth); - } - if s == LIVELINESS_LEASE_DURATION { - return Ok(Self::LivelinessLeaseDuration); - } - if s == AVOID_R2_NAMESPACE_CONVENTIONS { - return Ok(Self::AvoidR2NamespaceConventions); - } - Err(ParseQoSPlicyKindError { - reason: format!("Invalid qos policy kind in {}", s), - }) - } -} diff --git a/crates/rmw/src/qos_profiles.rs b/crates/rmw/src/qos_profiles.rs deleted file mode 100644 index 7af6471..0000000 --- a/crates/rmw/src/qos_profiles.rs +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use std::time::Duration; - -use crate::ret_types::RetType; -use crate::time::duration_unspecified; -use crate::types::{ - QoSDurabilityPolicy, QoSHistoryPolicy, QoSLivelinessPolicy, QoSReliabilityPolicy, -}; - -pub const QOS_POLICY_DEPTH_SYSTEM_DEFAULT: usize = 0; - -/// R2 MiddleWare quality of service profile. -#[derive(Debug, Clone, PartialEq)] -pub struct QoSProfile { - pub history: QoSHistoryPolicy, - - /// Size of the message queue. - pub depth: usize, - - /// Reliabiilty QoS policy setting. - pub reliability: QoSReliabilityPolicy, - - /// Durability QoS policy setting. - pub durability: QoSDurabilityPolicy, - - /// The period at which messages are expected to be sent/received. - pub deadline: Duration, - - /// The age at which messages are considered expired and no longer valid. - pub lifespan: Duration, - - /// Liveliness QoS policy setting - pub liveliness: QoSLivelinessPolicy, - - /// The time within which the RMW node or publisher must show that it is alive. - pub liveliness_lease_duration: Duration, - - /// If true, any R2 specific namespacing conventions will be circumvented. - pub avoid_r2_namespace_conventions: bool, -} - -impl QoSProfile { - #[inline] - pub fn sensor_data() -> Self { - QoSProfile { - history: QoSHistoryPolicy::KeepLast, - depth: 5, - reliability: QoSReliabilityPolicy::BestEffort, - durability: QoSDurabilityPolicy::Volatile, - deadline: duration_unspecified(), - lifespan: duration_unspecified(), - liveliness: QoSLivelinessPolicy::SystemDefault, - liveliness_lease_duration: duration_unspecified(), - avoid_r2_namespace_conventions: false, - } - } - - #[inline] - pub fn parameters() -> Self { - QoSProfile { - history: QoSHistoryPolicy::KeepLast, - depth: 1000, - reliability: QoSReliabilityPolicy::Reliable, - durability: QoSDurabilityPolicy::Volatile, - deadline: duration_unspecified(), - lifespan: duration_unspecified(), - liveliness: QoSLivelinessPolicy::SystemDefault, - liveliness_lease_duration: duration_unspecified(), - avoid_r2_namespace_conventions: false, - } - } - - #[inline] - pub fn services_default() -> Self { - QoSProfile { - history: QoSHistoryPolicy::KeepLast, - depth: 10, - reliability: QoSReliabilityPolicy::Reliable, - durability: QoSDurabilityPolicy::Volatile, - deadline: duration_unspecified(), - lifespan: duration_unspecified(), - liveliness: QoSLivelinessPolicy::SystemDefault, - liveliness_lease_duration: duration_unspecified(), - avoid_r2_namespace_conventions: false, - } - } - - #[inline] - pub fn parameter_events() -> Self { - QoSProfile { - history: QoSHistoryPolicy::KeepLast, - depth: 1000, - reliability: QoSReliabilityPolicy::Reliable, - durability: QoSDurabilityPolicy::Volatile, - deadline: duration_unspecified(), - lifespan: duration_unspecified(), - liveliness: QoSLivelinessPolicy::SystemDefault, - liveliness_lease_duration: duration_unspecified(), - avoid_r2_namespace_conventions: false, - } - } - - #[inline] - pub fn system_default() -> Self { - QoSProfile { - history: QoSHistoryPolicy::SystemDefault, - depth: QOS_POLICY_DEPTH_SYSTEM_DEFAULT, - reliability: QoSReliabilityPolicy::SystemDefault, - durability: QoSDurabilityPolicy::SystemDefault, - deadline: duration_unspecified(), - lifespan: duration_unspecified(), - liveliness: QoSLivelinessPolicy::SystemDefault, - liveliness_lease_duration: duration_unspecified(), - avoid_r2_namespace_conventions: false, - } - } - - #[inline] - pub fn unknown() -> Self { - QoSProfile { - history: QoSHistoryPolicy::Unknown, - depth: QOS_POLICY_DEPTH_SYSTEM_DEFAULT, - reliability: QoSReliabilityPolicy::Unknown, - durability: QoSDurabilityPolicy::Unknown, - deadline: duration_unspecified(), - lifespan: duration_unspecified(), - liveliness: QoSLivelinessPolicy::Unknown, - liveliness_lease_duration: duration_unspecified(), - avoid_r2_namespace_conventions: false, - } - } -} - -impl Default for QoSProfile { - fn default() -> Self { - QoSProfile { - history: QoSHistoryPolicy::KeepLast, - depth: 10, - reliability: QoSReliabilityPolicy::Reliable, - durability: QoSDurabilityPolicy::Volatile, - deadline: duration_unspecified(), - lifespan: duration_unspecified(), - liveliness: QoSLivelinessPolicy::SystemDefault, - liveliness_lease_duration: duration_unspecified(), - avoid_r2_namespace_conventions: false, - } - } -} - -#[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum QoSCompatibilityType { - /// QoS policies are compatible - Ok = 0, - - /// QoS policies may not be compatible - Warning, - - /// QoS policies are not compatible - Error, -} - -pub trait QoSProfileTrait { - /// Check if two QoS profiles are compatible. - /// - /// Two QoS profiles are compatible if a publisher and subcription - /// using the QoS policies can communicate with each other. - /// - /// If any of the profile policies has the value "system default" or "unknown", then it may not be - /// possible to determine the compatibilty. - /// In this case, the output parameter `compatibility` is set to `Warning` - /// and `reason` is populated. - /// - /// If there is a compatibility warning or error, and a buffer is provided for `reason`, then an - /// explanation of all warnings and errors will be populated into the buffer, separated by semi-colons (`;`). - /// Errors will appear before warnings in the string buffer. - /// If the provided buffer is not large enough, this function will still write to the buffer, up to - /// the `reason_size` number of characters. - /// Therefore, it is possible that not all errors and warnings are communicated if the buffer size limit is reached. - /// A buffer size of 2048 should be more than enough to capture all possible errors and warnings. - /// - /// Return `RET_OK` if the check was successful, - /// or return `RET_ERROR` if there is an unexpected error. - fn check_compatible( - profile: &QoSProfile, - other: &QoSProfile, - compatibility: &mut QoSCompatibilityType, - reason: &mut String, - ) -> RetType; -} diff --git a/crates/rmw/src/ret_types.rs b/crates/rmw/src/ret_types.rs deleted file mode 100644 index 58c4a39..0000000 --- a/crates/rmw/src/ret_types.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -/// Return code for rmw functions -pub type RetType = i32; - -/// The operation ran as expected -pub const RET_OK: RetType = 0; -/// Generic error to indicate operation could not complete successfully -pub const RET_ERROR: RetType = 1; -/// The operation was halted early because it exceeded its timeout critera -pub const RET_TIMEOUT: RetType = 2; -/// The operation or event handling is not supported. -pub const RET_UNSUPPORTED: RetType = 3; - -/// Failed to allocate memory -pub const RET_BAD_ALLOC: RetType = 10; -/// Argument to function was invalid -pub const RET_INVALID_ARGUMENT: RetType = 11; -/// Incorrect rmw implementation. -pub const RET_INCORRECT_RMW_IMPLEMENTATION: RetType = 12; - -// rmw node specific ret codes in 2XX -/// Failed to find node name -// Using same return code than in rcl -pub const RET_NODE_NAME_NON_EXISTENT: RetType = 203; diff --git a/crates/rmw/src/rmw.rs b/crates/rmw/src/rmw.rs deleted file mode 100644 index 411aa9c..0000000 --- a/crates/rmw/src/rmw.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -/// Root trait to wrapper global or general methods. -pub trait RmwTrait { - /// Get the name of the rmw implementation being used. - /// - /// Return Name of rmw implementation. - fn get_implementation_identifier() -> &'static str; - - /// Get the unique serialization format for this middleware. - /// - /// Return the format in which binary data is serialized. - /// One middleware can only have one encoding. - /// In contrast to the implementation identifier, the serialization format can be equal between - /// multiple RMW implementations. - /// This means, that the same binary messages can be deserialized by RMW implementations with the - /// same format. - /// - /// Return serialization format. - fn get_serialization_format() -> &'static str; -} diff --git a/crates/rmw/src/security_options.rs b/crates/rmw/src/security_options.rs deleted file mode 100644 index 6608fdf..0000000 --- a/crates/rmw/src/security_options.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use std::ffi::{OsStr, OsString}; - -#[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum SecurityEnforcementPolicy { - Permissive = 0, - Enforce, -} - -#[derive(Debug, Clone, PartialEq)] -pub struct SecurityOptions { - policy: SecurityEnforcementPolicy, - security_root_path: OsString, -} - -impl SecurityOptions { - /// Get zero initialized security options. - #[inline] - pub fn zero_initialized() -> Self { - Self::default() - } - - pub fn policy(&self) -> SecurityEnforcementPolicy { - self.policy - } - - pub fn security_root_path(&self) -> &OsStr { - &self.security_root_path - } - - /// Set the security root path for the given security options. - pub fn set_security_root_path>(&mut self, security_root_path: T) { - self.security_root_path.clear(); - self.security_root_path.push(security_root_path.as_ref()); - } -} - -impl Default for SecurityOptions { - /// Get default initialized security options. - fn default() -> Self { - Self { - policy: SecurityEnforcementPolicy::Permissive, - security_root_path: OsString::new(), - } - } -} diff --git a/crates/rmw/src/serialized_message.rs b/crates/rmw/src/serialized_message.rs deleted file mode 100644 index 59e5505..0000000 --- a/crates/rmw/src/serialized_message.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use crate::ret_types::RetType; - -/// Serialized message as a string of bytes. -#[derive(Debug, Default, Clone)] -pub struct SerializedMessage(Vec); - -impl SerializedMessage { - #[inline] - pub fn new() -> Self { - Self(Vec::new()) - } - - #[inline] - pub fn with_capacity(capacity: usize) -> Self { - Self(Vec::with_capacity(capacity)) - } - - /// Resizes the `SerializedMessage` in-place so that `len` is equal to `new_len`. - #[inline] - pub fn resize(&mut self, new_size: usize) { - self.0.resize(new_size, 0); - } - - /// Returns the number of elements in the message, also referred to as its ‘length’. - #[inline] - pub fn len(&self) -> usize { - self.0.len() - } -} - -pub trait SerializedMessageTrait { - /// Compute the size of a serialized message. - fn get_serialized_message_size( - //const rosidl_message_type_support_t * type_support, - //const rosidl_runtime_c__Sequence__bound * message_bounds, - size: &mut usize, - ) -> RetType; - - /// Serialize an R2 message into a SerializedMessage. - fn serialize( - r2_message: *const u8, - //const rosidl_message_type_support_t * type_support, - serialized_message: &mut SerializedMessage, - ) -> RetType; - - /// Deserialize a ROS message. - //TODO(Shaohua): Replace usize with &mut [u8] - fn deserialize( - serialized_message: &SerializedMessage, - //const rosidl_message_type_support_t * type_support, - r2_message: usize, - ) -> RetType; -} diff --git a/crates/rmw/src/time.rs b/crates/rmw/src/time.rs deleted file mode 100644 index bb93440..0000000 --- a/crates/rmw/src/time.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use std::time::Duration; - -// Re-export types. -pub use r2utils::time::{DurationValue, TimePointValue}; - -/// Constant representing an infinite duration. -#[inline] -pub fn duration_infinite() -> Duration { - Duration::new(9223372036, 854775807) -} - -#[inline] -pub fn duration_unspecified() -> Duration { - Duration::new(0, 0) -} diff --git a/crates/rmw/src/topic_endpoint_info.rs b/crates/rmw/src/topic_endpoint_info.rs deleted file mode 100644 index 0db349d..0000000 --- a/crates/rmw/src/topic_endpoint_info.rs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use crate::qos_profiles::QoSProfile; -use crate::ret_types; -use crate::types::{EndpointType, GID_STORAGE_SIZE}; - -/// A data structure that encapsulates the node name, node namespace, -/// topic_type, gid, and qos_profile of publishers and subscriptions -/// for a topic. -#[derive(Debug, Clone)] -pub struct TopicEndpointInfo { - /// Name of the node - pub node_name: String, - - /// Namespace of the node - pub node_namespace: String, - - /// The associated topic type - pub topic_type: String, - - /// The endpoint type - pub endpoint_type: EndpointType, - - /// The GID of the endpoint - pub endpoint_gid: [u8; GID_STORAGE_SIZE], - - /// QoS profile of the endpoint - pub qos_profile: QoSProfile, -} - -impl TopicEndpointInfo { - /// Return zero initialized topic endpoint info data structure. - /// - /// Endpoint type will be invalid. - /// Endpoint QoS profile will be the system default. - pub fn zero_initialized() -> Self { - Self::default() - } - - /// Set the topic type in the given topic endpoint info data structure. - /// - /// This functions allocates memory and copies the value of the `topic_type` - /// argument to set the data structure `topic_type` member. - pub fn set_topic_type(&mut self, topic_type: &str) -> ret_types::RetType { - if topic_type.is_empty() { - log::error!("topic_type is empty"); - return ret_types::RET_INVALID_ARGUMENT; - } - self.topic_type.clear(); - self.topic_type.push_str(topic_type); - ret_types::RET_OK - } - /// Set the node name in the given topic endpoint info data structure. - /// - /// This functions allocates memory and copies the value of the `node_name` - /// argument to set the data structure `node_name` member. - pub fn set_node_name(&mut self, node_name: &str) -> ret_types::RetType { - if node_name.is_empty() { - log::error!("node_name is empty"); - return ret_types::RET_INVALID_ARGUMENT; - } - self.node_name.clear(); - self.node_name.push_str(node_name); - ret_types::RET_OK - } - /// Set the endpoint type in the given topic endpoint info data structure. - /// - /// This functions assigns the value of the `type` argument to the data structure - /// `endpoint_type` member. - pub fn set_endpoint_type(&mut self, endpoint_type: EndpointType) -> ret_types::RetType { - self.endpoint_type = endpoint_type; - ret_types::RET_OK - } - - /// Set the endpoint gid in the given topic endpoint info data structure. - /// - /// This functions copies the value of the `gid` argument to the data structure - /// `endpoint_gid` member. - pub fn set_gid(&mut self, gid: &[u8]) -> ret_types::RetType { - if gid.len() > GID_STORAGE_SIZE { - log::error!("size is more than GID_STORAGE_SIZE"); - return ret_types::RET_INVALID_ARGUMENT; - } - self.endpoint_gid[0..gid.len()].copy_from_slice(gid); - ret_types::RET_OK - } - - /// Set the endpoint QoS profile in the given topic endpoint info data structure. - /// - /// This functions assigns the value of the `qos_profile` argument to the data structure - /// `qos_profile` member. - pub fn set_qos_profile(&mut self, qos_profile: &QoSProfile) -> ret_types::RetType { - self.qos_profile = qos_profile.clone(); - ret_types::RET_OK - } -} - -impl Default for TopicEndpointInfo { - fn default() -> Self { - Self { - node_name: String::new(), - node_namespace: String::new(), - topic_type: String::new(), - endpoint_type: EndpointType::Invalid, - endpoint_gid: [0; GID_STORAGE_SIZE], - qos_profile: QoSProfile::system_default(), - } - } -} diff --git a/crates/rmw/src/topic_endpoint_info_array.rs b/crates/rmw/src/topic_endpoint_info_array.rs deleted file mode 100644 index 59c59d5..0000000 --- a/crates/rmw/src/topic_endpoint_info_array.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use super::topic_endpoint_info::TopicEndpointInfo; - -/// Array of topic endpoint information -#[derive(Debug, Default)] -pub struct TopicEndpointInfoArray(Vec); diff --git a/crates/rmw/src/types/client.rs b/crates/rmw/src/types/client.rs deleted file mode 100644 index 19e4cea..0000000 --- a/crates/rmw/src/types/client.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use super::ServiceInfo; -use crate::ret_types::RetType; - -/// A handle to an rmw service client -#[derive(Debug)] -pub struct Client { - /// The name of the rmw implementation - pub implementation_identifier: String, - - /// Type erased pointer to this service client - //void * data; - pub data: *const u8, - - /// The name of this service as exposed to the r2 graph - pub service_name: String, -} - -pub trait ClientTrait { - /// Send an R2 service request. - fn send_request(client: &Client, ros_request: *const u8, sequence_id: &mut i64) -> RetType; - - /// Take an incoming R2 service response. - fn take_response( - client: &Client, - request_header: &mut ServiceInfo, - ros_response: usize, - taken: &mut bool, - ) -> RetType; -} diff --git a/crates/rmw/src/types/durability_policy.rs b/crates/rmw/src/types/durability_policy.rs deleted file mode 100644 index 87669aa..0000000 --- a/crates/rmw/src/types/durability_policy.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use std::fmt; - -const SYSTEM_DEFAULT: &str = "system_default"; -const TRANSIENT_LOCAL: &str = "transient_local"; -const VOLATILE: &str = "volatile"; - -/// QoS durability enumerations describing how samples persist -#[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum QoSDurabilityPolicy { - /// Impplementation specific default - SystemDefault = 0, - - /// The rmw publisher is responsible for persisting samples for “late-joining” subscribers - TransientLocal, - - /// Samples are not persistent - Volatile, - - /// Durability policy has not yet been set - Unknown, -} - -impl fmt::Display for QoSDurabilityPolicy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - Self::SystemDefault => SYSTEM_DEFAULT, - Self::TransientLocal => TRANSIENT_LOCAL, - Self::Volatile => VOLATILE, - Self::Unknown => "", - }; - write!(f, "{}", s) - } -} - -impl QoSDurabilityPolicy { - pub fn parse(s: &str) -> Self { - if s == SYSTEM_DEFAULT { - return Self::SystemDefault; - } - if s == TRANSIENT_LOCAL { - return Self::TransientLocal; - } - if s == VOLATILE { - return Self::Volatile; - } - Self::Unknown - } -} diff --git a/crates/rmw/src/types/gid.rs b/crates/rmw/src/types/gid.rs deleted file mode 100644 index be0d70c..0000000 --- a/crates/rmw/src/types/gid.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use crate::ret_types::RetType; - -/// 24 bytes is the most memory needed to represent the GID by any current -/// implementation. It may need to be increased in the future. -pub const GID_STORAGE_SIZE: usize = 24; - -/// R2 graph ID of the topic. -#[derive(Debug)] -pub struct Gid { - /// Name of the rmw implementation - pub implementation_identifier: String, - - /// Byte data Gid value - pub data: [u8; GID_STORAGE_SIZE], -} - -pub trait GidTrait { - /// Check if two unique identifiers (gids) are equal. - fn compare_gids_equal(gid1: &Gid, gid2: &Gid, result: &mut bool) -> RetType; -} diff --git a/crates/rmw/src/types/guard_condition.rs b/crates/rmw/src/types/guard_condition.rs deleted file mode 100644 index c58918d..0000000 --- a/crates/rmw/src/types/guard_condition.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use crate::init::ContextTrait; -use crate::ret_types::RetType; - -/// Handle for an rmw guard condition -#[derive(Debug)] -pub struct GuardCondition { - /// The name of the rmw implementation - pub implementation_identifier: String, - - /// Type erased pointer to this guard condition - //void * data; - pub data: *const u8, - - /// rmw context associated with this guard condition - pub context: dyn ContextTrait, -} - -/// Array of guard condition handles. -/// -/// An array of void * pointers representing type-erased middleware-specific guard conditions. -/// The number of non-null entries may be smaller than the allocated size of the array. -/// The number of guard conditions represented may be smaller than the allocated size of the array. -/// The creator of this struct is responsible for allocating and deallocating the array. -#[derive(Debug)] -pub struct GuardConditions(Vec); - -pub trait GuardConditionTrait { - fn trigger(guard_condition: &GuardCondition) -> RetType; -} diff --git a/crates/rmw/src/types/history_policy.rs b/crates/rmw/src/types/history_policy.rs deleted file mode 100644 index e18ef75..0000000 --- a/crates/rmw/src/types/history_policy.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use std::fmt; - -const SYSTEM_DEFAULT: &str = "system_default"; -const KEEP_LAST: &str = "keep_last"; -const KEEP_ALL: &str = "keep_all"; - -/// QoS history enumerations describing how samples endure. -#[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum QoSHistoryPolicy { - /// Implementation default for history policy - SystemDefault = 0, - - /// Only store up to a maximum number of samples, dropping oldest once max is exceeded - KeepLast, - - /// Store all samples, subject to resource limits - KeepAll, - - /// History policy has not yet been set - Unknown, -} - -impl fmt::Display for QoSHistoryPolicy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - Self::SystemDefault => SYSTEM_DEFAULT, - Self::KeepLast => KEEP_LAST, - Self::KeepAll => KEEP_ALL, - Self::Unknown => "", - }; - write!(f, "{}", s) - } -} - -impl QoSHistoryPolicy { - pub fn parse(s: &str) -> Self { - if s == SYSTEM_DEFAULT { - return Self::SystemDefault; - } - if s == KEEP_LAST { - return Self::KeepLast; - } - if s == KEEP_ALL { - return Self::KeepAll; - } - Self::Unknown - } -} diff --git a/crates/rmw/src/types/liveliness_policy.rs b/crates/rmw/src/types/liveliness_policy.rs deleted file mode 100644 index c6359c2..0000000 --- a/crates/rmw/src/types/liveliness_policy.rs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use std::fmt; - -const SYSTEM_DEFAULT: &str = "system_default"; -const AUTOMATIC: &str = "automatic"; -const MANUAL_BY_TOPIC: &str = "manual_by_topic"; - -/// QoS liveliness enumerations that describe a publisher's reporting policy for its alive status. -/// For a subscriber, these are its requirements for its topic's publishers. -#[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum QoSLivelinessPolicy { - /// Implementation specific default - SystemDefault = 0, - - /// The signal that establishes a Topic is alive comes from the R2 rmw layer. - Automatic = 1, - - /// Explicitly asserting node liveliness is required in this case. - #[deprecated( - since = "0.1", - note = "Use `ManualByTopic` if manually asserted liveliness is needed." - )] - ManualByNode = 2, - - /// The signal that establishes a Topic is alive is at the Topic level. Only publishing a message - /// on the Topic or an explicit signal from the application to assert liveliness on the Topic - /// will mark the Topic as being alive. - ManualByTopic = 3, - - /// Liveliness policy has not yet been set - Unknown = 4, -} - -impl fmt::Display for QoSLivelinessPolicy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - Self::SystemDefault => SYSTEM_DEFAULT, - Self::Automatic => AUTOMATIC, - Self::ManualByTopic => MANUAL_BY_TOPIC, - _ => "", - }; - write!(f, "{}", s) - } -} - -impl QoSLivelinessPolicy { - pub fn parse(s: &str) -> Self { - if s == SYSTEM_DEFAULT { - return Self::SystemDefault; - } - if s == AUTOMATIC { - return Self::Automatic; - } - if s == MANUAL_BY_TOPIC { - return Self::ManualByTopic; - } - Self::Unknown - } -} diff --git a/crates/rmw/src/types/mod.rs b/crates/rmw/src/types/mod.rs deleted file mode 100644 index 5586be1..0000000 --- a/crates/rmw/src/types/mod.rs +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use crate::time::TimePointValue; - -mod client; -mod durability_policy; -mod gid; -mod guard_condition; -mod history_policy; -mod liveliness_policy; -mod node; -mod publisher; -mod publisher_options; -mod reliability_policy; -mod service; -mod subscription; -mod subscription_options; -mod wait_set; - -pub use client::Client; -pub use durability_policy::QoSDurabilityPolicy; -pub use gid::{Gid, GID_STORAGE_SIZE}; -pub use guard_condition::{GuardCondition, GuardConditions}; -pub use history_policy::QoSHistoryPolicy; -pub use liveliness_policy::QoSLivelinessPolicy; -pub use node::{NodeBaseTrait, NodeTrait}; -pub use publisher::{PublisherBaseTrait, PublisherTrait}; -pub use publisher_options::PublisherOptions; -pub use reliability_policy::QoSReliabilityPolicy; -pub use service::Service; -pub use subscription::Subscription; -pub use subscription_options::SubscriptionOptions; -pub use wait_set::WaitSet; - -/// Endpoint enumeration type -#[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum EndpointType { - /// Endpoint type has not yet been set - Invalid = 0, - - /// Creates and publishes messages to the R2 topic - Publisher, - - /// Listens for and receives messages from a topic - Subscription, -} - -/// Unique network flow endpoints requirement enumeration -#[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum UniqueNetworkFlowEndpointsRequirement { - /// Unique network flow endpoints not required - NotRequired = 0, - - /// Unique network flow endpoins strictly required. - /// Error if not provided by RMW implementation. - StrictlyRequired, - - /// Unique network flow endpoints optionally required. - /// No error if not provided RMW implementation. - OptionallyRequired, - - /// Unique network flow endpoints requirement decided by system. - SystemDefault, -} - -/// Array of subscriber handles. -/// -/// An array of void * pointers representing type-erased middleware-specific subscriptions. -/// The number of non-null entries may be smaller than the allocated size of the array. -/// The number of subscriptions represented may be smaller than the allocated size of the array. -/// The creator of this struct is responsible for allocating and deallocating the array. -#[derive(Debug)] -pub struct Subscriptions(Vec); - -/// Array of service handles. -/// -/// An array of void * pointers representing type-erased middleware-specific services. -/// The number of non-null entries may be smaller than the allocated size of the array. -/// The number of services represented may be smaller than the allocated size of the array. -/// The creator of this struct is responsible for allocating and deallocating the array. -#[derive(Debug)] -pub struct Services(Vec); - -/// Array of client handles. -/// -/// An array of void * pointers representing type-erased middleware-specific clients. -/// The number of non-null entries may be smaller than the allocated size of the array. -/// The number of clients represented may be smaller than the allocated size of the array. -/// The creator of this struct is responsible for allocating and deallocating the array. -#[derive(Debug)] -pub struct Clients(Vec); - -/// An rmw service request identifier -#[derive(Debug)] -pub struct RequestId { - /// The guid of the writer associated with this request - pub writer_guid: [i8; 16], - - /// Sequence number of this service - pub sequence_number: i64, -} - -/// Meta-data for a service-related take. -#[derive(Debug)] -pub struct ServiceInfo { - pub source_timestamp: TimePointValue, - pub received_timestamp: TimePointValue, - pub request_id: RequestId, -} - -/// Information describing an rmw message -#[derive(Debug)] -pub struct MessageInfo { - pub source_timestamp: TimePointValue, - pub received_timestamp: TimePointValue, - pub publisher_gid: Gid, - - /// Whether this message is from intra_process communication or not - pub from_intra_process: bool, -} diff --git a/crates/rmw/src/types/node.rs b/crates/rmw/src/types/node.rs deleted file mode 100644 index 6fb589f..0000000 --- a/crates/rmw/src/types/node.rs +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use crate::init::ContextTrait; -use crate::names_and_types::NamesAndTypes; -use crate::qos_profiles::QoSProfile; -use crate::ret_types::RetType; -use crate::topic_endpoint_info_array::TopicEndpointInfoArray; -use crate::types::{ - Client, GuardCondition, PublisherOptions, PublisherTrait, Service, Subscription, - SubscriptionOptions, -}; - -/// Structure which encapsulates an rmw node -pub trait NodeBaseTrait { - /// Name of the rmw implementation - fn implementation_identifier(&self) -> &str; - - /// Type erased pointer to this node's data. - fn data(&self) -> &[u8]; - - /// A concise name of this rmw node for identification. - fn name(&self) -> &str; - - /// The namespace of this rmw node. - fn namespace_(&self) -> &str; - - /// Context information about node's init specific information. - fn context(&self) -> Option<&dyn ContextTrait>; -} - -pub trait NodeTrait: NodeBaseTrait { - /// Return all topic names and types for which a given remote node has subscriptions. - fn get_subscriber_names_and_types_by_node( - &self, - node_name: &str, - node_namespace: &str, - no_demangle: bool, - ) -> Result<&NamesAndTypes, RetType>; - - /// Return all topic names and types for which a given remote node has publishers. - fn get_publisher_names_and_types_by_node( - &self, - node_name: &str, - node_namespace: &str, - no_demangle: bool, - ) -> Result<&NamesAndTypes, RetType>; - - /// Return all service names and types for which a given remote node has servers. - fn get_service_names_and_types_by_node( - &self, - node_name: &str, - node_namespace: &str, - ) -> Result<&NamesAndTypes, RetType>; - - /// Return all service names and types for which a given remote node has clients. - fn get_client_names_and_types_by_node( - &self, - node_name: &str, - node_namespace: &str, - ) -> Result<&NamesAndTypes, RetType>; - - /// Return all service names and types in the ROS graph. - fn get_service_names_and_types(&self) -> Result<&NamesAndTypes, RetType>; - - /// Return all topic names and types in the ROS graph. - fn get_topic_names_and_types(&self, no_demangle: bool) -> Result<&NamesAndTypes, RetType>; - - /// Retrieve endpoint information for each known publisher of a given topic. - fn get_publishers_info_by_topic( - &self, - topic_name: &str, - no_mangle: bool, - ) -> Result<&TopicEndpointInfoArray, RetType>; - - /// Retrieve endpoint information for each known subscription of a given topic. - fn get_subscriptions_info_by_topic( - &self, - topic_name: &str, - no_mangle: bool, - ) -> Result<&TopicEndpointInfoArray, RetType>; - - /// Finalize a given node handle, reclaim the resources, and deallocate the node handle. - fn destroy_node(self) -> RetType; - - /// Return a guard condition which is triggered when the ROS graph changes. - // TODO(Shaohua): Returns Option>> - fn get_graph_guard_condition(&self) -> Option>; - - /// Create a publisher and return a handle to that publisher. - fn create_publisher( - &mut self, - type_support: &dyn r2idl::MessageTypeSupportTrait, - topic_name: &str, - qos_profile: &QoSProfile, - publisher_options: &PublisherOptions, - ) -> Result; - - /// Finalize a given publisher handle, reclaim the resources, and deallocate the publisher handle. - fn destroy_publisher(&mut self, publisher: dyn PublisherTrait) -> RetType; - - /// Create a subscription and return a handle to that subscription. - fn create_subscription( - &mut self, - type_support: &dyn r2idl::MessageTypeSupportTrait, - topic_name: &str, - qos_policies: &QoSProfile, - subscription_options: &SubscriptionOptions, - ) -> Result; - - /// Finalize a given subscription handle, reclaim the resources, and deallocate the subscription handle. - fn destroy_subscription(&mut self, subscription: Subscription) -> RetType; - - /// Create a service client that can send requests to and receive replies from a service server. - // TODO(Shaohua): - //const rosidl_service_type_support_t * type_support, - fn create_client( - &mut self, - service_name: &str, - qos_policies: &QoSProfile, - ) -> Result; - - /// Destroy and unregister a service client from its node. - fn destroy_client(&mut self, client: Client) -> RetType; - - /// Create a service server that can receive requests from and send replies to a service client. - // TODO(Shaohua): - //const rosidl_service_type_support_t * type_support, - fn create_service( - &mut self, - service_name: &str, - qos_profile: &QoSProfile, - ) -> Result; - - /// Destroy and unregister a service server from its node. - fn destroy_service(&mut self, service: Service) -> RetType; - - /// Return the name and namespace of all nodes in the R2 graph. - fn get_node_names(&self) -> Result<(&[String], &[String]), RetType>; - - /// Return the name, namespae, and enclave name of all nodes in the R2 graph. - fn get_node_names_with_enclaves(&self) -> Result<(&[String], &[String], &[String]), RetType>; - - /// Count the number of known publishers matching a topic name. - fn count_publishers(&self, topic_name: &str) -> Result; - - /// Count the number of known subscribers matching a topic name. - fn count_subscribers(&self, topic_name: &str) -> Result; - - /// Check if a service server is available for the given service client. - fn service_server_is_available(&self, client: &Client) -> Result; -} diff --git a/crates/rmw/src/types/publisher.rs b/crates/rmw/src/types/publisher.rs deleted file mode 100644 index c392cef..0000000 --- a/crates/rmw/src/types/publisher.rs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use super::{Gid, NodeBaseTrait, PublisherOptions}; -use crate::network_flow_endpoint_array::NetworkFlowEndpointArray; -use crate::qos_profiles::QoSProfile; -use crate::ret_types::{self, RetType}; -use crate::serialized_message::SerializedMessage; - -pub type MessagePointer = usize; - -/// Structure which encapsulates an rmw publisher -pub trait PublisherBaseTrait { - /// Name of the rmw implementation - fn implementation_identifier(&self) -> &str; - - /// Type erased pointer to this publisher's data - fn data(&self) -> &[u8]; - - /// The name of the R2 topic this publisher publishes to - fn topic_name(&self) -> &str; - - /// Publisher options. - /// - /// The options structure passed to [`NodeBaseTrait::create_publisher()`] should be - /// assigned to this field by the rmw implementation. - /// The fields should not be modified after creation, but - /// the contents of the options structure may or may not be const, i.e. - /// shallow const-ness. - /// This field is not marked const to avoid any const casting during setup. - /// - /// [`NodeBaseTrait::create_publisher()`]: NodeBaseTrait#tymethod.create_publisher - fn options(&self) -> &PublisherOptions; - - /// Indicate whether this publisher supports loaning messages - fn can_loan_messages(&self) -> bool; -} - -pub trait PublisherTrait: PublisherBaseTrait { - /// Get network flow endpoints of a publisher. - /// - /// Query the underlying middleware for a given publisher's network flow endpoints. - /// - /// Return [`ret_types::RET_OK`] if successful, - /// or return [`ret_types::RET_INVALID_ARGUMENT`] if any argument is null, - /// return [`ret_types::RET_UNSUPPORTED`] if not supported, - /// or return [`ret_types::RET_ERROR`] if an unexpected error occurs. - fn get_network_flow_points(&self, array: &mut NetworkFlowEndpointArray) -> RetType; - - /// Borrow a loaned R2 message. - /// - /// This message is owned by the middleware, that will keep it alive - /// (i.e. in valid memory space) until the caller publishes it - /// using [`Self::publish_loaned_message()`] or returns it using - /// [`Self::return_loaned_message_from_publisher()`]. - fn borrow_loaned_message( - &self, - type_support: &dyn r2idl::MessageTypeSupportTrait, - r2_message: MessagePointer, - ) -> RetType; - - /// Return a loaned message previously borrowed from a publisher. - fn return_loaned_message_from_publisher(&self, loaned_message: MessagePointer) -> RetType; - - /// Publish an R2 message. - /// - /// Send an R2 message to all subscriptions with matching QoS policies using the given publisher. - fn publish(&mut self, r2_message: MessagePointer) -> RetType; - - /// Publish a loaned R2 message. - fn publish_loaned_message(&mut self, r2_messge: MessagePointer) -> RetType; - - /// Retrieve the number of matched subscriptions to a publisher. - fn count_matched_subscriptions(&self) -> Result; - - /// Retrieve the actual qos settings of the publisher. - fn get_actual_qos(&self) -> Result<&QoSProfile, RetType>; - - /// Publish a R2 message as a byte stream. - fn publish_serialized_message(&mut self, serialized_message: &SerializedMessage) -> RetType; - - /// Manually assert that this Publisher is alive (for QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC) - fn assert_liveliness(&self) -> RetType; - - /// Get the unique identifier (gid) of a publisher. - fn get_gid_for_publisher(&self) -> Result<&Gid, RetType>; -} diff --git a/crates/rmw/src/types/publisher_options.rs b/crates/rmw/src/types/publisher_options.rs deleted file mode 100644 index 7da225d..0000000 --- a/crates/rmw/src/types/publisher_options.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use super::UniqueNetworkFlowEndpointsRequirement; - -/// Options that can be used to configure the creation of a publisher in rmw. -#[derive(Debug)] -pub struct PublisherOptions { - /// Used to pass rmw implementation specific resources during publisher creation. - /** - * This field is type erased (rather than forward declared) because it will - * usually be a non-owned reference to an language specific object, e.g. - * C++ it may be a polymorphic class that only the rmw implementation can use. - * - * The resource pointed to here needs to outlive this options structure, and - * any rmw_publisher objects that are created using it, as they copy this - * structure and may use this payload throughout their lifetime. - */ - // FIXME(Shaohua): - //void * rmw_specific_publisher_payload; - pub rmw_specific_publisher_payload: usize, - - /// Require middleware to generate unique network flow endpoints. - /** - * Unique network flow endpoints are required to differentiate the QoS provided by - * networks for flows between publishers and subscribers in communicating - * nodes. - * Default value is RMW_UNIQUE_NETWORK_FLOW_ENDPOINTS_NOT_REQUIRED. - */ - pub require_unique_network_flow_endpoints: UniqueNetworkFlowEndpointsRequirement, -} - -impl Default for PublisherOptions { - fn default() -> Self { - Self { - // TODO(Shaohua): Replace with pointers. - rmw_specific_publisher_payload: 0, - require_unique_network_flow_endpoints: - UniqueNetworkFlowEndpointsRequirement::NotRequired, - } - } -} diff --git a/crates/rmw/src/types/reliability_policy.rs b/crates/rmw/src/types/reliability_policy.rs deleted file mode 100644 index c40cb55..0000000 --- a/crates/rmw/src/types/reliability_policy.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use std::fmt; - -const SYSTEM_DEFAULT: &str = "system_default"; -const RELIABLE: &str = "reliable"; -const BEST_EFFORT: &str = "best_effort"; - -#[repr(u8)] -#[derive(Debug, Clone, Copy, Hash, PartialEq)] -pub enum QoSReliabilityPolicy { - /// Implementation specific default - SystemDefault, - - /// Guarantee that samples are delivered, may retry multiple times. - Reliable, - - /// Attempt to deliver samples, but some may be lost if the network is not robust - BestEffort, - - /// Reliability policy has not yet been set - Unknown, -} - -impl fmt::Display for QoSReliabilityPolicy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - Self::SystemDefault => SYSTEM_DEFAULT, - Self::Reliable => RELIABLE, - Self::BestEffort => BEST_EFFORT, - Self::Unknown => "", - }; - write!(f, "{}", s) - } -} - -impl QoSReliabilityPolicy { - pub fn parse(s: &str) -> Self { - if s == SYSTEM_DEFAULT { - return Self::SystemDefault; - } - if s == RELIABLE { - return Self::Reliable; - } - if s == BEST_EFFORT { - return Self::BestEffort; - } - Self::Unknown - } -} diff --git a/crates/rmw/src/types/service.rs b/crates/rmw/src/types/service.rs deleted file mode 100644 index 94fa36c..0000000 --- a/crates/rmw/src/types/service.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use crate::ret_types::RetType; -use crate::types::{RequestId, ServiceInfo}; - -/// A handle to an rmw service -#[derive(Debug)] -pub struct Service { - /// The name of the rmw implementation - pub implementation_identifier: String, - - /// Type erased pointer to this service - //void * data; - pub data: *const u8, - - /// The name of this service as exposed to the r2 graph - pub service_name: String, -} - -pub trait ServiceTrait { - /// Take an incoming ROS service request. - fn take_request( - service: &Service, - request_header: &mut ServiceInfo, - ros_request: usize, - taken: &mut bool, - ) -> RetType; - - /// Send a ROS service response. - fn send_response( - service: &Service, - request_header: &mut RequestId, - ros_response: usize, - ) -> RetType; -} diff --git a/crates/rmw/src/types/subscription.rs b/crates/rmw/src/types/subscription.rs deleted file mode 100644 index 60d91b5..0000000 --- a/crates/rmw/src/types/subscription.rs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use super::SubscriptionOptions; -use crate::message_sequence::{MessageInfoSequence, MessageSequence}; -use crate::network_flow_endpoint_array::NetworkFlowEndpointArray; -use crate::qos_profiles::QoSProfile; -use crate::ret_types::RetType; -use crate::serialized_message::SerializedMessage; -use crate::types::MessageInfo; - -#[derive(Debug)] -pub struct Subscription { - /// Name of the rmw implementation - pub implementation_identifier: String, - - /// Type erased pointer to this subscription - //void * data; - pub data: usize, - - /// Name of the r2 topic this subscription listens to - pub topic_name: String, - - /// Subscription options. - /// - /// The options structure passed to rmw_create_subscription() should be - /// assigned to this field by the rmw implementation. - /// The fields should not be modified after creation, but - /// the contents of the options structure may or may not be const, i.e. - /// shallow const-ness. - /// This field is not marked const to avoid any const casting during setup. - pub options: SubscriptionOptions, - - /// Indicates whether this subscription can loan messages - pub can_loan_messages: bool, -} - -pub trait SubscriptionTrait { - /// Get network flow endpoints of a subscription. - /// - /// Query the underlying middleware for a given subscription's network flow endpoints. - /// return `RET_OK` if successful, or return `RET_INVALID_ARGUMENT` if any argument is null, - /// or return `RET_UNSUPPORTED` if not supported, or return `RET_ERROR` if an unexpected error occurs. - fn get_network_flow_endpoints( - subscription: &Subscription, - array: &mut NetworkFlowEndpointArray, - ) -> RetType; - - /// Retrieve the number of matched publishers to a subscription. - fn count_matched_publishers( - subscription: &Subscription, - publisher_count: &mut usize, - ) -> RetType; - - /// Retrieve the actual qos settings of the subscription. - fn get_actual_qos(subscription: &Subscription, qos: &mut QoSProfile) -> RetType; - - /// Take an incoming ROS message. - fn take(subscription: &Subscription, ros_message: usize, taken: &mut bool) -> RetType; - - /// Take an incoming ROS message with its metadata. - fn take_with_info( - subscription: &Subscription, - ros_message: usize, - taken: &mut bool, - message_info: &mut MessageInfo, - ) -> RetType; - - /// Take multiple incoming ROS messages with their metadata. - fn take_sequence( - subscription: &Subscription, - count: usize, - message_sequence: &mut MessageSequence, - message_info_sequence: &mut MessageInfoSequence, - taken: &mut usize, - ) -> RetType; - - /// Take an incoming ROS message as a byte stream. - fn take_serialized_message( - subscription: &Subscription, - serialized_message: &mut SerializedMessage, - taken: &mut bool, - ) -> RetType; - - /// Take an incoming ROS message as a byte stream with its metadata. - fn take_serialized_message_with_info( - subscription: &Subscription, - serialized_message: &mut SerializedMessage, - taken: &mut bool, - message_info: &mut MessageInfo, - ) -> RetType; - - /// Take an incoming ROS message, loaned by the middleware. - fn take_loaned_message( - subscription: &Subscription, - loaned_message: usize, - taken: &mut bool, - ) -> RetType; - - /// Take a loaned message and with its additional message information. - fn take_loaned_message_with_info( - subscription: &Subscription, - loaned_message: usize, - taken: &mut bool, - message_info: &mut MessageInfo, - ) -> RetType; - - /// Return a loaned ROS message previously taken from a subscription. - fn return_loaned_message_from_subscription( - subscription: &Subscription, - loaned_message: usize, - ) -> RetType; -} diff --git a/crates/rmw/src/types/subscription_options.rs b/crates/rmw/src/types/subscription_options.rs deleted file mode 100644 index 4cd51fc..0000000 --- a/crates/rmw/src/types/subscription_options.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use super::UniqueNetworkFlowEndpointsRequirement; - -/// Options that can be used to configure the creation of a subscription in rmw. -#[derive(Debug)] -pub struct SubscriptionOptions { - /// Used to pass rmw implementation specific resources during subscription creation. - /// - /// All the same details and restrictions of this field in - /// `PublisherOptions` apply to this struct as well. - /// rmw_publisher_options_t.rmw_specific_publisher_payload - // TODO(Shaohua): Replace with fat pointer - //void * rmw_specific_subscription_payload; - pub rmw_specific_subscription_payload: usize, - - /// If true then the middleware should not deliver data from local publishers. - /// - /// This setting is most often used when data should only be received from - /// remote nodes, especially to avoid "double delivery" when both intra- and - /// inter- process communication is taking place. - /// - /// The definition of local is somewhat vague at the moment. - /// Right now it means local to the node, and that definition works best, but - /// may become more complicated when/if participants map to a context instead. - pub ignore_local_publications: bool, - - /// Require middleware to generate unique network flow endpoints. - /// - /// Unique network flow endpoints are required to differentiate the QoS provided by - /// networks for flows between publishers and subscribers in communicating - /// nodes. - /// Default value is RMW_UNIQUE_NETWORK_FLOW_ENDPOINTS_NOT_REQUIRED. - pub require_unique_network_flow_endpoints: UniqueNetworkFlowEndpointsRequirement, -} - -impl Default for SubscriptionOptions { - fn default() -> Self { - Self { - rmw_specific_subscription_payload: 0, - ignore_local_publications: false, - require_unique_network_flow_endpoints: - UniqueNetworkFlowEndpointsRequirement::NotRequired, - } - } -} diff --git a/crates/rmw/src/types/wait_set.rs b/crates/rmw/src/types/wait_set.rs deleted file mode 100644 index ccb520f..0000000 --- a/crates/rmw/src/types/wait_set.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use std::time::Duration; - -use super::{Clients, GuardConditions, Services, Subscriptions}; -use crate::event::Events; -use crate::ret_types::RetType; - -/// Container for guard conditions to be waited on -#[derive(Debug)] -pub struct WaitSet { - /// The name of the rmw implementation - pub implementation_identifier: String, - - /// The guard condition to be waited on - pub guard_conditions: Box, - - /// Type erased pointer to this wait set's data - //void * data; - pub data: *const u8, -} - -pub trait WaitSetTrait { - /// Destroy a wait set. - fn destroy(wait_set: &mut WaitSet) -> RetType; - - /// Waits on sets of different entities and returns when one is ready. - fn wait( - subscriptions: &mut Subscriptions, - guard_conditions: GuardConditions, - services: &mut Services, - clients: &mut Clients, - events: &mut Events, - wait_set: &mut WaitSet, - wait_timeout: &Duration, - ) -> RetType; -} diff --git a/crates/rmw/src/validate_namespace.rs b/crates/rmw/src/validate_namespace.rs deleted file mode 100644 index 80cc443..0000000 --- a/crates/rmw/src/validate_namespace.rs +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -use crate::validate_topic_name::{ - validate_topic_name, TopicNameError, TopicNameErrorType, TOPIC_NAME_MAX_LENGTH, -}; - -/// An additional 2 characters are reserved for the shortest possible topic, e.g. `/X`. -pub const NAMESPACE_MAX_LENGTH: usize = TOPIC_NAME_MAX_LENGTH - 2; - -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum NamespaceErrorType { - /// Node name is empty. - EmptyString, - - /// Not starts with `/`. - NotAbsolute, - - /// Must not ends with `/`. - EndsWithForwardSlash, - - /// Only alphanumeric characters and underscores are allowed. - ContainsUnallowedChars, - - /// A slash must not be followed by another slash. - ContainsRepeatedForwardSlash, - - /// Must not start with a number. - StartsWithNumber, - - /// Length of node name is larger than 255. - TooLong, -} - -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct NamespaceError { - reason: NamespaceErrorType, - invalid_index: usize, -} - -impl NamespaceError { - pub fn new(reason: NamespaceErrorType, invalid_index: usize) -> Self { - Self { - reason, - invalid_index, - } - } - - pub fn reason(&self) -> NamespaceErrorType { - self.reason - } - - pub fn invalid_index(&self) -> usize { - self.invalid_index - } -} - -impl From for NamespaceError { - fn from(err: TopicNameError) -> Self { - match err.reason() { - TopicNameErrorType::EmptyString => { - NamespaceError::new(NamespaceErrorType::EmptyString, err.invalid_index()) - } - TopicNameErrorType::NotAbsolute => { - NamespaceError::new(NamespaceErrorType::NotAbsolute, err.invalid_index()) - } - TopicNameErrorType::EndsWithForwardSlash => NamespaceError::new( - NamespaceErrorType::EndsWithForwardSlash, - err.invalid_index(), - ), - TopicNameErrorType::ContainsUnallowedChars => NamespaceError::new( - NamespaceErrorType::ContainsUnallowedChars, - err.invalid_index(), - ), - TopicNameErrorType::ContainsRepeatedForwardSlash => NamespaceError::new( - NamespaceErrorType::ContainsRepeatedForwardSlash, - err.invalid_index(), - ), - TopicNameErrorType::StartsWithNumber => { - NamespaceError::new(NamespaceErrorType::StartsWithNumber, err.invalid_index()) - } - TopicNameErrorType::TooLong => { - NamespaceError::new(NamespaceErrorType::TooLong, err.invalid_index()) - } - } - } -} - -/// Determine if a given namespace is valid. -/// -/// The `NamespaceErrorType::TooLong` is guaranteed to be checked last, -/// such that if you get that result, then you can assume all other checks -/// succeeded. -/// This is done so that the length limit can be treated as a warning rather -/// than an error if desired. -pub fn validate_namespace(namespace: &str) -> Result<(), NamespaceError> { - // Special case for root namespace - if namespace == "/" { - return Ok(()); - } - - // All other cases should pass the validate topic name test. - if let Err(err) = validate_topic_name(namespace) { - let err: NamespaceError = err.into(); - // Ignores `TooLong` error as it will be rechecked below. - if err.reason() != NamespaceErrorType::TooLong { - return Err(err); - } - } - - // check if the namespace is too long last, since it might be a soft invalidation. - if namespace.len() > NAMESPACE_MAX_LENGTH { - return Err(NamespaceError::new( - NamespaceErrorType::TooLong, - NAMESPACE_MAX_LENGTH - 1, - )); - } - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_valid_namespace() { - assert!(validate_namespace("/").is_ok()); - assert!(validate_namespace("/basename_only").is_ok()); - assert!(validate_namespace("/with_one/hierarchy").is_ok()); - } - - #[test] - fn test_empty_namespace() { - assert_eq!( - validate_namespace(""), - Err(NamespaceError::new(NamespaceErrorType::EmptyString, 0)) - ); - } - - #[test] - fn test_not_absolute() { - assert_eq!( - validate_namespace("not_absolute"), - Err(NamespaceError::new(NamespaceErrorType::NotAbsolute, 0)) - ); - - assert_eq!( - validate_namespace("not/absolute"), - Err(NamespaceError::new(NamespaceErrorType::NotAbsolute, 0)) - ); - } - - #[test] - fn test_ends_with_forward_slash() { - assert_eq!( - validate_namespace("/ends/with/"), - Err(NamespaceError::new( - NamespaceErrorType::EndsWithForwardSlash, - 10 - )) - ); - } - - #[test] - fn test_unallowed_characters() { - assert_eq!( - validate_namespace("/~/unexpanded_tilde"), - Err(NamespaceError::new( - NamespaceErrorType::ContainsUnallowedChars, - 1 - )) - ); - - assert_eq!( - validate_namespace("/unexpanded_sub/{node}"), - Err(NamespaceError::new( - NamespaceErrorType::ContainsUnallowedChars, - 16 - )) - ); - - assert_eq!( - validate_namespace("/question?"), - Err(NamespaceError::new( - NamespaceErrorType::ContainsUnallowedChars, - 9 - )) - ); - - assert_eq!( - validate_namespace("/with spaces"), - Err(NamespaceError::new( - NamespaceErrorType::ContainsUnallowedChars, - 5 - )) - ); - } - - #[test] - fn test_repeated_forward_slashes() { - assert_eq!( - validate_namespace("/repeated//slashes"), - Err(NamespaceError::new( - NamespaceErrorType::ContainsRepeatedForwardSlash, - 10 - )) - ); - } - - #[test] - fn test_starts_with_number() { - assert_eq!( - validate_namespace("/9starts_with_number"), - Err(NamespaceError::new(NamespaceErrorType::StartsWithNumber, 1)) - ); - - assert_eq!( - validate_namespace("/starts/42with/number"), - Err(NamespaceError::new(NamespaceErrorType::StartsWithNumber, 8)) - ); - } - - #[test] - fn test_topic_too_long() { - let invalid_long_topic: String = "a".repeat(NAMESPACE_MAX_LENGTH + 1); - assert_eq!( - validate_namespace(&invalid_long_topic), - Err(NamespaceError::new(NamespaceErrorType::NotAbsolute, 0)) - ); - - let valid_long_topic = "/".to_owned() + &invalid_long_topic; - assert_eq!( - validate_namespace(&valid_long_topic), - Err(NamespaceError::new( - NamespaceErrorType::TooLong, - NAMESPACE_MAX_LENGTH - 1 - )) - ); - } -} diff --git a/crates/rmw/src/validate_node_name.rs b/crates/rmw/src/validate_node_name.rs deleted file mode 100644 index cea3990..0000000 --- a/crates/rmw/src/validate_node_name.rs +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -/// Length of node name must not exceed 255 characters. -pub const NODE_NAME_MAX_LENGTH: usize = 255; - -#[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum NodeNameErrorType { - /// Node name is empty. - EmptyString, - - /// Only alphanumeric characters and underscores are allowed. - ContainsUnallowedChars, - - /// Must not start with a number. - StartsWithNumber, - - /// Length of node name is larger than 255. - TooLong, -} - -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct NodeNameError { - reason: NodeNameErrorType, - invalid_index: usize, -} - -impl NodeNameError { - pub fn new(reason: NodeNameErrorType, invalid_index: usize) -> Self { - Self { - reason, - invalid_index, - } - } - - pub fn reason(&self) -> NodeNameErrorType { - self.reason - } - - pub fn invalid_index(&self) -> usize { - self.invalid_index - } -} - -/// Determine if a node name is valid. -/// -/// The `NodeNameErrorType::TooLong` is guaranteed to be checked last, such -/// that if you get that result, then you can assume all other checks succeeded. -/// This is done so that the length limit can be treated as a warning rather -/// than an error if desired. -/// -/// Node names must follow these rules: -/// - must not be an empty string -/// - must only contain alphanumeric characters and underscores (a-z|A-Z|0-9|_) -/// - must not start with a number -pub fn validate_node_name(node_name: &str) -> Result<(), NodeNameError> { - if node_name.is_empty() { - return Err(NodeNameError::new(NodeNameErrorType::EmptyString, 0)); - } - - // Check for allowed characters. - for (idx, c) in node_name.chars().enumerate() { - if !(c.is_ascii_alphanumeric() || c == '_') { - return Err(NodeNameError::new( - NodeNameErrorType::ContainsUnallowedChars, - idx, - )); - } - } - - // This is the case where the name starts with a number, i.e. [0-9]. - if node_name.starts_with(|c: char| c.is_digit(10)) { - return Err(NodeNameError::new(NodeNameErrorType::StartsWithNumber, 0)); - } - - // Check if the node name is too long last, since it might be a soft invalidation - if node_name.len() > NODE_NAME_MAX_LENGTH { - return Err(NodeNameError::new( - NodeNameErrorType::TooLong, - NODE_NAME_MAX_LENGTH - 1, - )); - } - - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_valid_node_name() { - assert!(validate_node_name("nodename").is_ok()); - } - - #[test] - fn test_empty_node_name() { - assert_eq!( - validate_node_name(""), - Err(NodeNameError::new(NodeNameErrorType::EmptyString, 0)) - ); - } - - #[test] - fn test_unallowed_chars() { - assert_eq!( - validate_node_name("node/name"), - Err(NodeNameError::new( - NodeNameErrorType::ContainsUnallowedChars, - 4 - )) - ); - - assert_eq!( - validate_node_name("node_{name}"), - Err(NodeNameError::new( - NodeNameErrorType::ContainsUnallowedChars, - 5 - )) - ); - - assert_eq!( - validate_node_name("~node_name"), - Err(NodeNameError::new( - NodeNameErrorType::ContainsUnallowedChars, - 0 - )) - ); - - assert_eq!( - validate_node_name("with spaces"), - Err(NodeNameError::new( - NodeNameErrorType::ContainsUnallowedChars, - 4 - )) - ); - - assert_eq!( - validate_node_name("with.periods"), - Err(NodeNameError::new( - NodeNameErrorType::ContainsUnallowedChars, - 4 - )) - ); - } - - #[test] - fn test_starts_with_number() { - assert_eq!( - validate_node_name("42node"), - Err(NodeNameError::new(NodeNameErrorType::StartsWithNumber, 0)) - ); - } - - #[test] - fn test_node_name_too_long() { - // Ensure the length is not the first error - let long_name: String = "0".repeat(NODE_NAME_MAX_LENGTH + 1); - assert_eq!( - validate_node_name(&long_name), - Err(NodeNameError::new(NodeNameErrorType::StartsWithNumber, 0)) - ); - - // Ensure length check works when there are no other issues - let long_name: String = "a".repeat(NODE_NAME_MAX_LENGTH + 1); - assert_eq!( - validate_node_name(&long_name), - Err(NodeNameError::new( - NodeNameErrorType::TooLong, - NODE_NAME_MAX_LENGTH - 1 - )) - ); - } -} diff --git a/crates/rmw/src/validate_topic_name.rs b/crates/rmw/src/validate_topic_name.rs deleted file mode 100644 index d73265b..0000000 --- a/crates/rmw/src/validate_topic_name.rs +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright (c) 2021 Xu Shaohua . All rights reserved. -// Use of this source is governed by General Public License that can be found -// in the LICENSE file. - -/// Length of topic name must not exceed `255 - 8` characters. -/// `8` characters are reversed for prefixes. -pub const TOPIC_NAME_MAX_LENGTH: usize = 255 - 8; - -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum TopicNameErrorType { - /// Topic name is empty. - EmptyString, - - /// Not starts with `/`. - NotAbsolute, - - /// Must not ends with `/`. - EndsWithForwardSlash, - - /// Only alphanumeric characters, underscores and slashes are allowed. - ContainsUnallowedChars, - - /// A slash must not be followed by another slash. - ContainsRepeatedForwardSlash, - - /// Must not start with a number. - /// A slash must not be followed by a number. - StartsWithNumber, - - /// Length of topic name is larger than `255 - 8`. - TooLong, -} - -#[derive(Debug, Clone, Copy, PartialEq)] -pub struct TopicNameError { - reason: TopicNameErrorType, - invalid_index: usize, -} - -impl TopicNameError { - pub fn new(reason: TopicNameErrorType, invalid_index: usize) -> Self { - Self { - reason, - invalid_index, - } - } - - pub fn reason(&self) -> TopicNameErrorType { - self.reason - } - - pub fn invalid_index(&self) -> usize { - self.invalid_index - } -} - -/// Determine if a given fully qualified topic name is valid. -/// -/// The `TopicNameErrorType::TooLong` is guaranteed to be checked last, such -/// that if you get that result, then you can assume all other checks succeeded. -/// This is done so that the length limit can be treated as a warning rather -/// than an error if desired. -/// -/// Topic names must follow these rules: -/// - must not be an empty string -/// - must only contain alphanumeric characters, underscores and slashes (a-z|A-Z|0-9|_/) -/// - must not start with a number -/// - must start with `/` -/// - must not end with `/` -pub fn validate_topic_name(topic_name: &str) -> Result<(), TopicNameError> { - if topic_name.is_empty() { - return Err(TopicNameError::new(TopicNameErrorType::EmptyString, 0)); - } - - if !topic_name.starts_with('/') { - return Err(TopicNameError::new(TopicNameErrorType::NotAbsolute, 0)); - } - - // Catches both '/foo/' and '/'. - if topic_name.ends_with('/') { - return Err(TopicNameError::new( - TopicNameErrorType::EndsWithForwardSlash, - topic_name.len() - 1, - )); - } - - // check for unallowed characters. - for (idx, c) in topic_name.chars().enumerate() { - if !(c.is_ascii_alphanumeric() || c == '_' || c == '/') { - return Err(TopicNameError::new( - TopicNameErrorType::ContainsUnallowedChars, - idx, - )); - } - } - - // Check for double '/' and tokens that start with a number. - let mut last_char_is_slash = false; - for (idx, c) in topic_name.chars().enumerate() { - if last_char_is_slash { - if c == '/' { - return Err(TopicNameError::new( - TopicNameErrorType::ContainsRepeatedForwardSlash, - idx, - )); - } else if c.is_digit(10) { - // This is the case where a '/' if followed by a number, i.e. [0-9]. - return Err(TopicNameError::new( - TopicNameErrorType::StartsWithNumber, - idx, - )); - } - } - - last_char_is_slash = c == '/'; - } - - // Check if the topic name is too long last, since it might be a soft invalidation. - if topic_name.len() > TOPIC_NAME_MAX_LENGTH { - return Err(TopicNameError::new( - TopicNameErrorType::TooLong, - TOPIC_NAME_MAX_LENGTH - 1, - )); - } - - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_valid_topic() { - assert!(validate_topic_name("/basename_only").is_ok()); - assert!(validate_topic_name("/with_one/namespace").is_ok()); - assert!(validate_topic_name("/with_double/namespaces/sep").is_ok()); - } - - #[test] - fn test_empty_topic_name() { - assert_eq!( - validate_topic_name(""), - Err(TopicNameError::new(TopicNameErrorType::EmptyString, 0)) - ); - } - - #[test] - fn test_not_absolute() { - assert_eq!( - validate_topic_name("not_absolute"), - Err(TopicNameError::new(TopicNameErrorType::NotAbsolute, 0)) - ); - - assert_eq!( - validate_topic_name("not/absolute"), - Err(TopicNameError::new(TopicNameErrorType::NotAbsolute, 0)) - ); - } - - #[test] - fn test_ends_with_forward_slash() { - assert_eq!( - validate_topic_name("/ends/with/"), - Err(TopicNameError::new( - TopicNameErrorType::EndsWithForwardSlash, - 10 - )) - ); - - assert_eq!( - validate_topic_name("/"), - Err(TopicNameError::new( - TopicNameErrorType::EndsWithForwardSlash, - 0 - )) - ); - } - - #[test] - fn test_unallowed_characters() { - assert_eq!( - validate_topic_name("/~/unexpected_tilde"), - Err(TopicNameError::new( - TopicNameErrorType::ContainsUnallowedChars, - 1 - )) - ); - - assert_eq!( - validate_topic_name("/unexpected_sub/{node}"), - Err(TopicNameError::new( - TopicNameErrorType::ContainsUnallowedChars, - 16 - )) - ); - - assert_eq!( - validate_topic_name("/question?"), - Err(TopicNameError::new( - TopicNameErrorType::ContainsUnallowedChars, - 9 - )) - ); - - assert_eq!( - validate_topic_name("/with spaces"), - Err(TopicNameError::new( - TopicNameErrorType::ContainsUnallowedChars, - 5 - )) - ); - } - - #[test] - fn test_repeated_forward_slashes() { - assert_eq!( - validate_topic_name("/repeated//slashes"), - Err(TopicNameError::new( - TopicNameErrorType::ContainsRepeatedForwardSlash, - 10 - )) - ); - } - - #[test] - fn test_starts_with_number() { - assert_eq!( - validate_topic_name("/9starts_with_number"), - Err(TopicNameError::new(TopicNameErrorType::StartsWithNumber, 1)) - ); - - assert_eq!( - validate_topic_name("/starts/42with/number"), - Err(TopicNameError::new(TopicNameErrorType::StartsWithNumber, 8)) - ); - } - - #[test] - fn test_topic_too_long() { - let invalid_long_topic: String = "a".repeat(TOPIC_NAME_MAX_LENGTH + 1); - assert_eq!( - validate_topic_name(&invalid_long_topic), - Err(TopicNameError::new(TopicNameErrorType::NotAbsolute, 0)) - ); - - let valid_but_long_topic = "/".to_owned() + &invalid_long_topic; - assert_eq!( - validate_topic_name(&valid_but_long_topic), - Err(TopicNameError::new( - TopicNameErrorType::TooLong, - TOPIC_NAME_MAX_LENGTH - 1 - )) - ); - } -}