-
-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Option::as_ref_or_else helper (#717)
* Modularize utils * Implement Option::as_{de,}ref_or_else * Changelog * Fix broken doclink * Use capturing format variables, thanks @NickLarsenNZ
- Loading branch information
Showing
7 changed files
with
255 additions
and
157 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/// This is a bash snippet, which adds two functions out of interest: | ||
/// | ||
/// 1. `prepare_signal_handlers` call this first to set up the needed traps | ||
/// 2. `wait_for_termination` waits for the PID you passed as the first argument to terminate | ||
/// | ||
/// An example use could be | ||
/// ```text | ||
/// {COMMON_BASH_TRAP_FUNCTIONS} | ||
/// echo "Run before startup" | ||
/// prepare_signal_handlers | ||
/// {hadoop_home}/bin/hdfs {role} & | ||
/// wait_for_termination $! | ||
/// echo "Run after termination" | ||
/// ``` | ||
pub const COMMON_BASH_TRAP_FUNCTIONS: &str = r#" | ||
prepare_signal_handlers() | ||
{ | ||
unset term_child_pid | ||
unset term_kill_needed | ||
trap 'handle_term_signal' TERM | ||
} | ||
handle_term_signal() | ||
{ | ||
if [ "${term_child_pid}" ]; then | ||
kill -TERM "${term_child_pid}" 2>/dev/null | ||
else | ||
term_kill_needed="yes" | ||
fi | ||
} | ||
wait_for_termination() | ||
{ | ||
set +e | ||
term_child_pid=$1 | ||
if [[ -v term_kill_needed ]]; then | ||
kill -TERM "${term_child_pid}" 2>/dev/null | ||
fi | ||
wait ${term_child_pid} 2>/dev/null | ||
trap - TERM | ||
wait ${term_child_pid} 2>/dev/null | ||
set -e | ||
} | ||
"#; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
use tracing::info; | ||
|
||
/// Prints helpful and standardized diagnostic messages. | ||
/// | ||
/// This method is meant to be called first thing in the `main` method of an Operator. | ||
/// | ||
/// # Usage | ||
/// | ||
/// Use the [`built`](https://crates.io/crates/built) crate and include it in your `main.rs` like this: | ||
/// | ||
/// ```text | ||
/// mod built_info { | ||
/// // The file has been placed there by the build script. | ||
/// include!(concat!(env!("OUT_DIR"), "/built.rs")); | ||
/// } | ||
/// ``` | ||
/// | ||
/// Then call this method in your `main` method: | ||
/// | ||
/// ```text | ||
/// stackable_operator::utils::print_startup_string( | ||
/// built_info::PKG_DESCRIPTION, | ||
/// built_info::PKG_VERSION, | ||
/// built_info::GIT_VERSION, | ||
/// built_info::TARGET, | ||
/// built_info::BUILT_TIME_UTC, | ||
/// built_info::RUSTC_VERSION, | ||
/// ); | ||
/// ``` | ||
pub fn print_startup_string( | ||
pkg_description: &str, | ||
pkg_version: &str, | ||
git_version: Option<&str>, | ||
target: &str, | ||
built_time: &str, | ||
rustc_version: &str, | ||
) { | ||
let git = match git_version { | ||
None => "".to_string(), | ||
Some(git) => format!(" (Git information: {git})"), | ||
}; | ||
info!("Starting {pkg_description}"); | ||
info!( | ||
"This is version {pkg_version}{git}, built for {target} by {rustc_version} at {built_time}", | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
pub mod bash; | ||
pub mod logging; | ||
mod option; | ||
mod url; | ||
|
||
#[deprecated( | ||
note = "renamed to stackable_operator::utils::bash::COMMON_BASH_TRAP_FUNCTIONS", | ||
since = "0.61.1" | ||
)] | ||
pub use self::bash::COMMON_BASH_TRAP_FUNCTIONS; | ||
#[deprecated( | ||
note = "renamed to stackable_operator::utils::logging::print_startup_string", | ||
since = "0.61.1" | ||
)] | ||
pub use self::logging::print_startup_string; | ||
|
||
pub use self::{option::OptionExt, url::UrlExt}; | ||
|
||
/// Returns the fully qualified controller name, which should be used when a single controller needs to be referred to uniquely. | ||
/// | ||
/// `operator` should be a FQDN-style operator name (for example: `zookeeper.stackable.tech`). | ||
/// `controller` should typically be the lower-case version of the primary resource that the | ||
/// controller manages (for example: `zookeepercluster`). | ||
pub(crate) fn format_full_controller_name(operator: &str, controller: &str) -> String { | ||
format!("{operator}_{controller}") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
use std::{borrow::Cow, ops::Deref}; | ||
|
||
#[cfg(doc)] | ||
use std::path::PathBuf; | ||
|
||
/// Extension methods for [`Option`]. | ||
pub trait OptionExt<T> { | ||
/// Returns a reference to the value if [`Some`], otherwise evaluates `default()`. | ||
/// | ||
/// Compared to [`Option::unwrap_or_else`], this saves having to [`Clone::clone`] the value to make the types line up. | ||
/// | ||
/// Consider using [`Self::as_deref_or_else`] instead if the type implements [`Deref`] (such as [`String`] or [`PathBuf`]). | ||
fn as_ref_or_else(&self, default: impl FnOnce() -> T) -> Cow<T> | ||
where | ||
T: Clone; | ||
|
||
/// Returns a reference to `self` if [`Some`], otherwise evaluates `default()`. | ||
/// | ||
/// Compared to [`Option::unwrap_or_else`], this saves having to [`Clone::clone`] the value to make the types line up. | ||
/// | ||
/// Consider using [`Self::as_ref_or_else`] instead if the type does not implement [`Deref`]. | ||
fn as_deref_or_else(&self, default: impl FnOnce() -> T) -> Cow<T::Target> | ||
where | ||
T: Deref, | ||
T::Target: ToOwned<Owned = T>; | ||
} | ||
|
||
impl<T> OptionExt<T> for Option<T> { | ||
fn as_ref_or_else(&self, default: impl FnOnce() -> T) -> Cow<T> | ||
where | ||
T: Clone, | ||
{ | ||
self.as_ref() | ||
.map_or_else(|| Cow::Owned(default()), Cow::Borrowed) | ||
} | ||
|
||
fn as_deref_or_else(&self, default: impl FnOnce() -> T) -> Cow<<T>::Target> | ||
where | ||
T: Deref, | ||
<T>::Target: ToOwned<Owned = T>, | ||
{ | ||
self.as_deref() | ||
.map_or_else(|| Cow::Owned(default()), Cow::Borrowed) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use std::borrow::Cow; | ||
|
||
use crate::utils::OptionExt as _; | ||
|
||
#[test] | ||
fn test_as_ref_or_else() { | ||
let maybe: Option<String> = None; | ||
let defaulted: Cow<String> = maybe.as_ref_or_else(|| "foo".to_string()); | ||
assert_eq!(defaulted, Cow::<String>::Owned("foo".to_string())); | ||
|
||
let maybe: Option<String> = Some("foo".to_string()); | ||
let defaulted: Cow<String> = maybe.as_ref_or_else(|| panic!()); | ||
assert_eq!(defaulted, Cow::<String>::Borrowed(&"foo".to_string())); | ||
} | ||
|
||
#[test] | ||
fn test_as_deref_or_else() { | ||
let maybe: Option<String> = None; | ||
let defaulted: Cow<str> = maybe.as_deref_or_else(|| "foo".to_string()); | ||
assert_eq!(defaulted, Cow::<str>::Owned("foo".to_string())); | ||
|
||
let maybe: Option<String> = Some("foo".to_string()); | ||
let defaulted: Cow<str> = maybe.as_deref_or_else(|| panic!()); | ||
assert_eq!(defaulted, Cow::<str>::Borrowed("foo")); | ||
} | ||
} |
Oops, something went wrong.