From 03a4776385776a45df384ac83a3421a6b2835f4a Mon Sep 17 00:00:00 2001 From: J-Loudet Date: Wed, 14 Feb 2024 13:26:02 +0100 Subject: [PATCH] doc(commons): improve documentation (#183) Signed-off-by: Julien Loudet --- zenoh-flow-commons/src/configuration.rs | 10 +++--- zenoh-flow-commons/src/deserialize.rs | 19 ++++++++++-- zenoh-flow-commons/src/identifiers.rs | 41 ++++++++++++++++++++++++- zenoh-flow-commons/src/lib.rs | 5 +++ zenoh-flow-commons/src/merge.rs | 6 ++++ zenoh-flow-commons/src/shared_memory.rs | 12 +++++++- zenoh-flow-commons/src/utils.rs | 9 ++++++ zenoh-flow-commons/src/vars.rs | 31 ++++++++++++++----- 8 files changed, 116 insertions(+), 17 deletions(-) diff --git a/zenoh-flow-commons/src/configuration.rs b/zenoh-flow-commons/src/configuration.rs index ce892bd0..8e68407a 100644 --- a/zenoh-flow-commons/src/configuration.rs +++ b/zenoh-flow-commons/src/configuration.rs @@ -16,8 +16,8 @@ use crate::merge::IMergeOverwrite; use serde::{Deserialize, Serialize}; use std::{ops::Deref, sync::Arc}; -/// A `Configuration` is a recursive key-value structure that allows modifying the behavior of a -/// node without altering its implementation. +/// A `Configuration` is a recursive key-value structure that allows modifying the behavior of a node without altering +/// its implementation. /// /// It is effectively a re-export of [serde_json::Value]. /// @@ -49,8 +49,8 @@ use std::{ops::Deref, sync::Arc}; // // NOTE: we take the `serde_json` representation because: // - JSON is the most supported representation when going online, -// - a `serde_json::Value` can be converted to a `serde_yaml::Value` whereas the opposite is not -// true (YAML introduces "tags" which are not supported by JSON). +// - a `serde_json::Value` can be converted to a `serde_yaml::Value` whereas the opposite is not true (YAML introduces +// "tags" which are not supported by JSON). #[derive(Default, Deserialize, Debug, Serialize, Clone, PartialEq, Eq)] pub struct Configuration(Arc); @@ -81,7 +81,7 @@ impl IMergeOverwrite for Configuration { Configuration(Arc::new(other.into())) } (_, _) => unreachable!( - "We are checking, when deserializing, that a Configuration is a JSON object." + "We are checking, when deserialising, that a Configuration is a JSON object." ), } } diff --git a/zenoh-flow-commons/src/deserialize.rs b/zenoh-flow-commons/src/deserialize.rs index e3a5e8aa..027792b1 100644 --- a/zenoh-flow-commons/src/deserialize.rs +++ b/zenoh-flow-commons/src/deserialize.rs @@ -21,6 +21,13 @@ use serde::Deserializer; use std::{str::FromStr, sync::Arc}; use zenoh_keyexpr::OwnedKeyExpr; +/// Deserialise, from a [String], an `Arc` that is guaranteed to be a valid Zenoh-Flow [NodeId](crate::NodeId) or +/// [PortId](crate::PortId). +/// +/// To be valid, the following properties must be upheld: +/// - the String does not contain any of the symbols: * # $ ? > +/// - the String is a valid Zenoh key expression in its canonical form (see +/// [autocanonize](zenoh_keyexpr::OwnedKeyExpr::autocanonize)). pub fn deserialize_id<'de, D>(deserializer: D) -> std::result::Result, D::Error> where D: Deserializer<'de>, @@ -33,10 +40,10 @@ Identifiers (for nodes or ports) in Zenoh-Flow must *not* contain any of the cha The identifier < {} > does not satisfy that condition. These characters, except for '>', have a special meaning in Zenoh and they could negatively impact Zenoh-Flow's -behavior. +behaviour. The character '>' is used as a separator when flattening a composite operator. Allowing it could also negatively impact -Zenoh-Flow's behavior. +Zenoh-Flow's behaviour. "#, id ))); @@ -58,6 +65,9 @@ Caused by: Ok(id.into()) } +/// Deserialise a bytes size leveraging the [bytesize] crate. +/// +/// This allows parsing, for instance, "1Ko" into "1024" bytes. For more example, see the [bytesize] crate. pub fn deserialize_size<'de, D>(deserializer: D) -> std::result::Result where D: Deserializer<'de>, @@ -78,6 +88,9 @@ where ))) } +/// Deserialise a duration in *microseconds* leveraging the [humantime] crate. +/// +/// This allows parsing, for instance, "1ms" as 1000 microseconds. pub fn deserialize_time<'de, D>(deserializer: D) -> std::result::Result where D: Deserializer<'de>, @@ -86,7 +99,7 @@ where let time_u128 = buf .parse::() .map_err(serde::de::Error::custom)? - .as_nanos(); + .as_micros(); u64::try_from(time_u128).map_err(|e| { serde::de::Error::custom(format!( diff --git a/zenoh-flow-commons/src/identifiers.rs b/zenoh-flow-commons/src/identifiers.rs index ca25f0e1..f2ccf952 100644 --- a/zenoh-flow-commons/src/identifiers.rs +++ b/zenoh-flow-commons/src/identifiers.rs @@ -22,7 +22,15 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; use zenoh_protocol::core::ZenohId; -/// A `NodeId` identifies a Node in a data flow. +/// A `NodeId` uniquely identifies a Node within a data flow. +/// +/// A `NodeId` additionally satisfies the following constraints: +/// - it does *not* contain any of the symbols: * # $ ? > +/// - it is a valid [canonical Zenoh key expression](zenoh_keyexpr::OwnedKeyExpr::autocanonize). +/// +/// # Performance +/// +/// A `NodeId` is encapsulated in an [Arc] rendering clone operations almost cost-free. #[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Hash)] pub struct NodeId(#[serde(deserialize_with = "deserialize_id")] Arc); @@ -53,6 +61,20 @@ impl From<&str> for NodeId { } /// A `PortId` identifies an `Input` or an `Output` of a Node. +/// +/// A `PortId` additionally satisfies the following constraints: +/// - it does *not* contain any of the symbols: * # $ ? > +/// - it is a valid [canonical Zenoh key expression](zenoh_keyexpr::OwnedKeyExpr::autocanonize). +/// +/// # Uniqueness +/// +/// A `PortId` does not need to be unique within a data flow. It should only be unique among the ports of the same node +/// and of the same type (i.e. `Input` or `Output`). +/// For instance, a node can have an `Input` and an `Output` with the same `PortId`. +/// +/// # Performance +/// +/// A `PortId` is encapsulated in an [Arc] rendering clone operations almost cost-free. #[derive(Debug, Clone, Hash, PartialEq, Eq, Deserialize, Serialize)] pub struct PortId(#[serde(deserialize_with = "deserialize_id")] Arc); @@ -82,11 +104,21 @@ impl From<&str> for PortId { } } +/// A `RuntimeId` uniquely identifies a Zenoh-Flow runtime within a Zenoh network. +/// +/// The `RuntimeId` structure simply wraps a [ZenohId]. Similar to a Uuid, this identifier is (with a high probability) +/// guaranteed to be unique within your infrastructure. +/// +/// A Zenoh-Flow runtime will, by default, reuse the [ZenohId] of the Zenoh +/// [session](https://docs.rs/zenoh/0.10.1-rc/zenoh/struct.Session.html) it will create to connect to the Zenoh network. #[derive(Debug, Clone, Hash, PartialEq, Eq, Deserialize, Serialize, Default)] #[repr(transparent)] pub struct RuntimeId(ZenohId); impl RuntimeId { + /// Generate a new random identifier, guaranteed (with a high probability) to be unique. + /// + /// This internally calls [ZenohId::rand]. pub fn rand() -> Self { Self(ZenohId::rand()) } @@ -122,6 +154,13 @@ impl FromStr for RuntimeId { } } +/// An `InstanceId` uniquely identifies a data flow instance. +/// +/// A data flow instance is created every time Zenoh-Flow is tasked to run a data flow. Each instance of the same data +/// flow will have a different `InstanceId`. +/// +/// Internally, it uses a [Uuid v4](uuid::Uuid::new_v4) that it wraps inside an [Arc]. This allows for almost cost-free +/// `clone` operations. #[derive(Debug, Clone, Hash, PartialEq, Eq, Deserialize, Serialize)] pub struct InstanceId(Arc); diff --git a/zenoh-flow-commons/src/lib.rs b/zenoh-flow-commons/src/lib.rs index ebdb390a..dde27994 100644 --- a/zenoh-flow-commons/src/lib.rs +++ b/zenoh-flow-commons/src/lib.rs @@ -12,6 +12,11 @@ // ZettaScale Zenoh Team, // +//! This crate centralises structures that are shared across Zenoh-Flow. +//! +//! ⚠️ This crate is intended for internal usage within Zenoh-Flow. All structures that are exposed in public +//! facing API are re-exposed in the relevant crates. + mod configuration; pub use configuration::Configuration; diff --git a/zenoh-flow-commons/src/merge.rs b/zenoh-flow-commons/src/merge.rs index 3ef66aaf..0a676c01 100644 --- a/zenoh-flow-commons/src/merge.rs +++ b/zenoh-flow-commons/src/merge.rs @@ -12,6 +12,12 @@ // ZettaScale Zenoh Team, // +/// Types which can be combined with another instance of the same type and for which, in case there are common elements, +/// the elements of `self` would be kept over those held by `other`. +/// +/// For instance, a map-like type with keys shared by both would see the associated values in `self` preserved. +/// +/// This trait is leveraged in Zenoh-Flow for the [Configuration](crate::Configuration) and the [Vars](crate::Vars). pub trait IMergeOverwrite { fn merge_overwrite(self, other: Self) -> Self; } diff --git a/zenoh-flow-commons/src/shared_memory.rs b/zenoh-flow-commons/src/shared_memory.rs index 80c93675..d355483d 100644 --- a/zenoh-flow-commons/src/shared_memory.rs +++ b/zenoh-flow-commons/src/shared_memory.rs @@ -17,9 +17,19 @@ use std::fmt::Display; use crate::deserialize::{deserialize_size, deserialize_time}; use serde::{Deserialize, Serialize}; +/// Structure to configure how Zenoh-Flow uses the [shared memory](https://docs.rs/zenoh-shm/0.10.1-rc/zenoh_shm/) +/// feature provided by Zenoh. +/// +/// This configuration is applied on a link basis +/// +/// A Zenoh-Flow runtime can be configured to always attempt to send data through shared-memory first. When this feature +/// is enabled this structure allows tweaking two aspects: (i) the size of the shared memory buffer Zenoh should +/// allocate and (ii) the back-off period. +/// +/// #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct SharedMemoryConfiguration { - /// Size, converted in bytes, of the shared memory buffer. + /// Size, converted in bytes, of the entire shared memory buffer. #[serde(deserialize_with = "deserialize_size")] pub size: usize, /// Duration, converted in nanoseconds, to wait before retrying the last operation. diff --git a/zenoh-flow-commons/src/utils.rs b/zenoh-flow-commons/src/utils.rs index 01e7fb25..19bdbb28 100644 --- a/zenoh-flow-commons/src/utils.rs +++ b/zenoh-flow-commons/src/utils.rs @@ -49,6 +49,15 @@ Currently supported file extensions are: } } +/// Attempts to parse an instance of `N` from the content of the file located at `path`, overwriting (or complementing) +/// the [Vars] declared in said file with the provided `vars`. +/// +/// This function is notably used to parse a data flow descriptor. Two file types are supported, identified by their +/// extension: +/// - JSON (`.json` file extension) +/// - YAML (`.yaml` or `.yml` extensions) +/// +/// This function does not impose writing *all* descriptor file, within the same data flow, in the same format. pub fn try_load_from_file(path: impl AsRef, vars: Vars) -> Result<(N, Vars)> where N: for<'a> Deserialize<'a>, diff --git a/zenoh-flow-commons/src/vars.rs b/zenoh-flow-commons/src/vars.rs index b0538b31..d55a20a2 100644 --- a/zenoh-flow-commons/src/vars.rs +++ b/zenoh-flow-commons/src/vars.rs @@ -19,16 +19,33 @@ use std::error::Error; use std::ops::Deref; use std::rc::Rc; -/// `Vars` is an internal structure that we use to expand the "mustache variables" in a descriptor -/// file. +/// `Vars` is an internal structure that we use to expand the "moustache variables" in a descriptor file. /// -/// Mustache variables take the form: "{{ var }}..." where the number of spaces after the '{{' and -/// before the '}}' do not matter. +/// Moustache variables take the form: `{{ var }}` where the number of spaces after the `{{` and before the `}}` do +/// not matter. /// /// We first parse the descriptor file to only extract the `vars` section and build a `HashMap` out of it. /// -/// We then load the descriptor file as a template and "render" it, substituting every "mustache -/// variable" with its corresponding value in the HashMap. +/// We then load the descriptor file as a template and "render" it, substituting every "moustache variable" with its +/// corresponding value in the HashMap. +/// +/// # Example (YAML) +/// +/// Declaration within a descriptor: +/// +/// ```yaml +/// vars: +/// BUILD: debug +/// DLL_EXT: so +/// ``` +/// +/// Its usage within the descriptor: +/// +/// ```yaml +/// sources: +/// - id: my-source +/// library: "file:///zenoh-flow/target/{{ BUILD }}/libmy_source.{{ DLL_EXT }}" +/// ``` #[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)] pub struct Vars { #[serde(default)] @@ -80,7 +97,7 @@ impl, U: AsRef> From> for Vars { } } -/// Parse a Vars from a string of the format "KEY=VALUE". +/// Parse a single [Var](Vars) from a string of the format "KEY=VALUE". pub fn parse_vars( s: &str, ) -> std::result::Result<(T, U), Box>