From 487c723b388dc8449bb34d16a4bc9d3b088767a7 Mon Sep 17 00:00:00 2001 From: Stan Bondi Date: Thu, 30 Jun 2022 12:28:25 +0200 Subject: [PATCH 1/2] feat(comms): add or_optional trait extension for RpcStatus --- comms/core/src/lib.rs | 1 + comms/core/src/protocol/rpc/status.rs | 30 +++++++++++++++++++++++++-- comms/core/src/traits.rs | 28 +++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 comms/core/src/traits.rs diff --git a/comms/core/src/lib.rs b/comms/core/src/lib.rs index 5622d9afb8..d72b52585a 100644 --- a/comms/core/src/lib.rs +++ b/comms/core/src/lib.rs @@ -55,6 +55,7 @@ pub mod utils; // TODO: Test utils should be part of a `tari_comms_test` crate // #[cfg(test)] pub mod test_utils; +pub mod traits; //---------------------------------- Re-exports --------------------------------------------// // Rather than requiring dependent crates to import dependencies for use with `tari_comms` we re-export them here. diff --git a/comms/core/src/protocol/rpc/status.rs b/comms/core/src/protocol/rpc/status.rs index 128e4fb5d8..5f7f0e979b 100644 --- a/comms/core/src/protocol/rpc/status.rs +++ b/comms/core/src/protocol/rpc/status.rs @@ -26,11 +26,11 @@ use log::*; use thiserror::Error; use super::RpcError; -use crate::proto; +use crate::{proto, traits::OrOptional}; const LOG_TARGET: &str = "comms::rpc::status"; -#[derive(Debug, Error, Clone)] +#[derive(Debug, Error, Clone, PartialEq, Eq)] pub struct RpcStatus { code: RpcStatusCode, details: String, @@ -141,6 +141,10 @@ impl RpcStatus { pub fn is_ok(&self) -> bool { self.code.is_ok() } + + pub fn is_not_found(&self) -> bool { + self.code.is_not_found() + } } impl Display for RpcStatus { @@ -202,6 +206,15 @@ impl RpcStatusResultExt for Result { } } +impl OrOptional for Result { + type Error = RpcStatus; + + fn or_optional(self) -> Result, Self::Error> { + self.map(Some) + .or_else(|status| if status.is_not_found() { Ok(None) } else { Err(status) }) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum RpcStatusCode { /// Request succeeded @@ -296,4 +309,17 @@ mod test { assert_eq!(RpcStatusCode::from(Conflict as u32), Conflict); assert_eq!(RpcStatusCode::from(123), InvalidRpcStatusCode); } + + #[test] + fn rpc_status_or_optional() { + assert!(Result::<(), RpcStatus>::Ok(()).or_optional().is_ok()); + assert_eq!( + Result::<(), _>::Err(RpcStatus::not_found("foo")).or_optional(), + Ok(None) + ); + assert_eq!( + Result::<(), _>::Err(RpcStatus::general("foo")).or_optional(), + Err(RpcStatus::general("foo")) + ); + } } diff --git a/comms/core/src/traits.rs b/comms/core/src/traits.rs new file mode 100644 index 0000000000..ea5b794615 --- /dev/null +++ b/comms/core/src/traits.rs @@ -0,0 +1,28 @@ +// Copyright 2022, The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/// Extension trait that typically converts Result to Result, Self::Error> +/// based on some implementer logic. +pub trait OrOptional { + type Error; + fn or_optional(self) -> Result, Self::Error>; +} From e1958a5dbcc51dea1b303b7e695fdaf6f159a851 Mon Sep 17 00:00:00 2001 From: Stan Bondi Date: Thu, 30 Jun 2022 12:29:13 +0200 Subject: [PATCH 2/2] fix(comms): fixup lifetimes which error in latest rust --- comms/core/src/tor/control_client/client.rs | 6 ++--- .../tor/control_client/commands/key_value.rs | 26 +++++++++---------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/comms/core/src/tor/control_client/client.rs b/comms/core/src/tor/control_client/client.rs index 1ab6a0e4a6..cb6fea357a 100644 --- a/comms/core/src/tor/control_client/client.rs +++ b/comms/core/src/tor/control_client/client.rs @@ -111,15 +111,13 @@ impl TorControlPortClient { } /// The GETCONF command. Returns configuration keys matching the `conf_name`. - #[allow(clippy::needless_lifetimes)] - pub async fn get_conf<'a>(&mut self, conf_name: &'a str) -> Result>, TorClientError> { + pub async fn get_conf(&mut self, conf_name: &'static str) -> Result>, TorClientError> { let command = commands::get_conf(conf_name); self.request_response(command).await } /// The GETINFO command. Returns configuration keys matching the `conf_name`. - #[allow(clippy::needless_lifetimes)] - pub async fn get_info<'a>(&mut self, key_name: &'a str) -> Result>, TorClientError> { + pub async fn get_info(&mut self, key_name: &'static str) -> Result>, TorClientError> { let command = commands::get_info(key_name); let response = self.request_response(command).await?; if response.is_empty() { diff --git a/comms/core/src/tor/control_client/commands/key_value.rs b/comms/core/src/tor/control_client/commands/key_value.rs index 2d181f4e2c..f80b1104d3 100644 --- a/comms/core/src/tor/control_client/commands/key_value.rs +++ b/comms/core/src/tor/control_client/commands/key_value.rs @@ -20,50 +20,48 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::{borrow::Cow, fmt, marker::PhantomData}; +use std::{borrow::Cow, fmt}; use crate::tor::control_client::{commands::TorCommand, error::TorClientError, parsers, response::ResponseLine}; /// The GETCONF command. /// /// This command is used to query the Tor proxy configuration file. -pub fn get_conf(query: &str) -> KeyValueCommand<'_, '_> { +pub fn get_conf(query: &str) -> KeyValueCommand<'_> { KeyValueCommand::new("GETCONF", &[query]) } /// The GETINFO command. /// /// This command is used to retrieve Tor proxy configuration keys. -pub fn get_info(key_name: &str) -> KeyValueCommand<'_, '_> { +pub fn get_info(key_name: &str) -> KeyValueCommand<'_> { KeyValueCommand::new("GETINFO", &[key_name]) } /// The SETEVENTS command. /// /// This command is used to set the events that tor will emit -pub fn set_events<'b>(event_types: &[&'b str]) -> KeyValueCommand<'static, 'b> { +pub fn set_events<'a>(event_types: &[&'a str]) -> KeyValueCommand<'a> { KeyValueCommand::new("SETEVENTS", event_types) } -pub struct KeyValueCommand<'a, 'b> { - command: &'a str, - args: Vec<&'b str>, - _lifetime: PhantomData<&'b ()>, +pub struct KeyValueCommand<'a> { + command: &'static str, + args: Vec<&'a str>, } -impl<'a, 'b> KeyValueCommand<'a, 'b> { - pub fn new(command: &'a str, args: &[&'b str]) -> Self { +impl<'a> KeyValueCommand<'a> { + pub fn new(command: &'static str, args: &[&'a str]) -> Self { Self { command, args: args.to_vec(), - _lifetime: PhantomData, } } } -impl<'a, 'b> TorCommand for KeyValueCommand<'a, 'b> { +impl<'a> TorCommand for KeyValueCommand<'a> { type Error = TorClientError; - type Output = Vec>; + type Output = Vec>; fn to_command_string(&self) -> Result { Ok(format!("{} {}", self.command, self.args.join(" "))) @@ -99,7 +97,7 @@ impl<'a, 'b> TorCommand for KeyValueCommand<'a, 'b> { } } -impl fmt::Display for KeyValueCommand<'_, '_> { +impl fmt::Display for KeyValueCommand<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f,