summaryrefslogtreecommitdiffstats
path: root/third_party/rust/clap_builder/src/util
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/clap_builder/src/util
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/clap_builder/src/util')
-rw-r--r--third_party/rust/clap_builder/src/util/any_value.rs127
-rw-r--r--third_party/rust/clap_builder/src/util/color.rs116
-rw-r--r--third_party/rust/clap_builder/src/util/flat_map.rs254
-rw-r--r--third_party/rust/clap_builder/src/util/flat_set.rs107
-rw-r--r--third_party/rust/clap_builder/src/util/graph.rs49
-rw-r--r--third_party/rust/clap_builder/src/util/id.rs164
-rw-r--r--third_party/rust/clap_builder/src/util/mod.rs47
-rw-r--r--third_party/rust/clap_builder/src/util/str_to_bool.rs21
8 files changed, 885 insertions, 0 deletions
diff --git a/third_party/rust/clap_builder/src/util/any_value.rs b/third_party/rust/clap_builder/src/util/any_value.rs
new file mode 100644
index 0000000000..6f1e3665e5
--- /dev/null
+++ b/third_party/rust/clap_builder/src/util/any_value.rs
@@ -0,0 +1,127 @@
+#[derive(Clone)]
+pub(crate) struct AnyValue {
+ inner: std::sync::Arc<dyn std::any::Any + Send + Sync + 'static>,
+ // While we can extract `TypeId` from `inner`, the debug repr is of a number, so let's track
+ // the type_name in debug builds.
+ id: AnyValueId,
+}
+
+impl AnyValue {
+ pub(crate) fn new<V: std::any::Any + Clone + Send + Sync + 'static>(inner: V) -> Self {
+ let id = AnyValueId::of::<V>();
+ let inner = std::sync::Arc::new(inner);
+ Self { inner, id }
+ }
+
+ pub(crate) fn downcast_ref<T: std::any::Any + Clone + Send + Sync + 'static>(
+ &self,
+ ) -> Option<&T> {
+ self.inner.downcast_ref::<T>()
+ }
+
+ pub(crate) fn downcast_into<T: std::any::Any + Clone + Send + Sync>(self) -> Result<T, Self> {
+ let id = self.id;
+ let value =
+ ok!(std::sync::Arc::downcast::<T>(self.inner).map_err(|inner| Self { inner, id }));
+ let value = std::sync::Arc::try_unwrap(value).unwrap_or_else(|arc| (*arc).clone());
+ Ok(value)
+ }
+
+ pub(crate) fn type_id(&self) -> AnyValueId {
+ self.id
+ }
+}
+
+impl std::fmt::Debug for AnyValue {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ f.debug_struct("AnyValue").field("inner", &self.id).finish()
+ }
+}
+
+#[derive(Copy, Clone)]
+pub struct AnyValueId {
+ type_id: std::any::TypeId,
+ #[cfg(debug_assertions)]
+ type_name: &'static str,
+}
+
+impl AnyValueId {
+ pub(crate) fn of<A: ?Sized + 'static>() -> Self {
+ Self {
+ type_id: std::any::TypeId::of::<A>(),
+ #[cfg(debug_assertions)]
+ type_name: std::any::type_name::<A>(),
+ }
+ }
+}
+
+impl PartialEq for AnyValueId {
+ fn eq(&self, other: &Self) -> bool {
+ self.type_id == other.type_id
+ }
+}
+
+impl Eq for AnyValueId {}
+
+impl PartialOrd for AnyValueId {
+ fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+ self.type_id.partial_cmp(&other.type_id)
+ }
+}
+
+impl PartialEq<std::any::TypeId> for AnyValueId {
+ fn eq(&self, other: &std::any::TypeId) -> bool {
+ self.type_id == *other
+ }
+}
+
+impl Ord for AnyValueId {
+ fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+ self.type_id.cmp(&other.type_id)
+ }
+}
+
+impl std::hash::Hash for AnyValueId {
+ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+ self.type_id.hash(state);
+ }
+}
+
+impl std::fmt::Debug for AnyValueId {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ #[cfg(not(debug_assertions))]
+ {
+ self.type_id.fmt(f)
+ }
+ #[cfg(debug_assertions)]
+ {
+ f.debug_struct(self.type_name).finish()
+ }
+ }
+}
+
+impl<'a, A: ?Sized + 'static> From<&'a A> for AnyValueId {
+ fn from(_: &'a A) -> Self {
+ Self::of::<A>()
+ }
+}
+
+#[cfg(test)]
+mod test {
+ #[test]
+ #[cfg(debug_assertions)]
+ fn debug_impl() {
+ use super::*;
+
+ assert_eq!(format!("{:?}", AnyValue::new(5)), "AnyValue { inner: i32 }");
+ }
+
+ #[test]
+ fn eq_to_type_id() {
+ use super::*;
+
+ let any_value_id = AnyValueId::of::<i32>();
+ let type_id = std::any::TypeId::of::<i32>();
+ assert_eq!(any_value_id, type_id);
+ }
+}
diff --git a/third_party/rust/clap_builder/src/util/color.rs b/third_party/rust/clap_builder/src/util/color.rs
new file mode 100644
index 0000000000..d13a6df9e2
--- /dev/null
+++ b/third_party/rust/clap_builder/src/util/color.rs
@@ -0,0 +1,116 @@
+use crate::builder::PossibleValue;
+use crate::derive::ValueEnum;
+
+/// Represents the color preferences for program output
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum ColorChoice {
+ /// Enables colored output only when the output is going to a terminal or TTY.
+ ///
+ /// **NOTE:** This is the default behavior of `clap`.
+ ///
+ /// # Platform Specific
+ ///
+ /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms).
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # #[cfg(feature = "color")] {
+ /// # use clap_builder as clap;
+ /// # use clap::{Command, ColorChoice};
+ /// Command::new("myprog")
+ /// .color(ColorChoice::Auto)
+ /// .get_matches();
+ /// # }
+ /// ```
+ Auto,
+
+ /// Enables colored output regardless of whether or not the output is going to a terminal/TTY.
+ ///
+ /// # Platform Specific
+ ///
+ /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms).
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # #[cfg(feature = "color")] {
+ /// # use clap_builder as clap;
+ /// # use clap::{Command, ColorChoice};
+ /// Command::new("myprog")
+ /// .color(ColorChoice::Always)
+ /// .get_matches();
+ /// # }
+ /// ```
+ Always,
+
+ /// Disables colored output no matter if the output is going to a terminal/TTY, or not.
+ ///
+ /// # Platform Specific
+ ///
+ /// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms)
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # #[cfg(feature = "color")] {
+ /// # use clap_builder as clap;
+ /// # use clap::{Command, ColorChoice};
+ /// Command::new("myprog")
+ /// .color(ColorChoice::Never)
+ /// .get_matches();
+ /// # }
+ /// ```
+ Never,
+}
+
+impl ColorChoice {
+ /// Report all `possible_values`
+ pub fn possible_values() -> impl Iterator<Item = PossibleValue> {
+ Self::value_variants()
+ .iter()
+ .filter_map(ValueEnum::to_possible_value)
+ }
+}
+
+impl Default for ColorChoice {
+ fn default() -> Self {
+ Self::Auto
+ }
+}
+
+impl std::fmt::Display for ColorChoice {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.to_possible_value()
+ .expect("no values are skipped")
+ .get_name()
+ .fmt(f)
+ }
+}
+
+impl std::str::FromStr for ColorChoice {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ for variant in Self::value_variants() {
+ if variant.to_possible_value().unwrap().matches(s, false) {
+ return Ok(*variant);
+ }
+ }
+ Err(format!("invalid variant: {s}"))
+ }
+}
+
+impl ValueEnum for ColorChoice {
+ fn value_variants<'a>() -> &'a [Self] {
+ &[Self::Auto, Self::Always, Self::Never]
+ }
+
+ fn to_possible_value(&self) -> Option<PossibleValue> {
+ Some(match self {
+ Self::Auto => PossibleValue::new("auto"),
+ Self::Always => PossibleValue::new("always"),
+ Self::Never => PossibleValue::new("never"),
+ })
+ }
+}
diff --git a/third_party/rust/clap_builder/src/util/flat_map.rs b/third_party/rust/clap_builder/src/util/flat_map.rs
new file mode 100644
index 0000000000..468f0a9d89
--- /dev/null
+++ b/third_party/rust/clap_builder/src/util/flat_map.rs
@@ -0,0 +1,254 @@
+#![allow(dead_code)]
+
+use std::borrow::Borrow;
+
+/// Flat (Vec) backed map
+///
+/// This preserves insertion order
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub(crate) struct FlatMap<K, V> {
+ keys: Vec<K>,
+ values: Vec<V>,
+}
+
+impl<K: PartialEq + Eq, V> FlatMap<K, V> {
+ pub(crate) fn new() -> Self {
+ Default::default()
+ }
+
+ pub(crate) fn insert(&mut self, key: K, mut value: V) -> Option<V> {
+ for (index, existing) in self.keys.iter().enumerate() {
+ if *existing == key {
+ std::mem::swap(&mut self.values[index], &mut value);
+ return Some(value);
+ }
+ }
+
+ self.insert_unchecked(key, value);
+ None
+ }
+
+ pub(crate) fn insert_unchecked(&mut self, key: K, value: V) {
+ self.keys.push(key);
+ self.values.push(value);
+ }
+
+ pub(crate) fn extend_unchecked(&mut self, iter: impl IntoIterator<Item = (K, V)>) {
+ for (key, value) in iter {
+ self.insert_unchecked(key, value);
+ }
+ }
+
+ pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
+ where
+ K: Borrow<Q>,
+ Q: Eq,
+ {
+ for existing in &self.keys {
+ if existing.borrow() == key {
+ return true;
+ }
+ }
+ false
+ }
+
+ pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
+ where
+ K: Borrow<Q>,
+ Q: std::hash::Hash + Eq,
+ {
+ self.remove_entry(key).map(|(_, v)| v)
+ }
+
+ pub fn remove_entry<Q: ?Sized>(&mut self, key: &Q) -> Option<(K, V)>
+ where
+ K: Borrow<Q>,
+ Q: std::hash::Hash + Eq,
+ {
+ let index = some!(self
+ .keys
+ .iter()
+ .enumerate()
+ .find_map(|(i, k)| (k.borrow() == key).then_some(i)));
+ let key = self.keys.remove(index);
+ let value = self.values.remove(index);
+ Some((key, value))
+ }
+
+ pub(crate) fn is_empty(&self) -> bool {
+ self.keys.is_empty()
+ }
+
+ pub fn entry(&mut self, key: K) -> Entry<K, V> {
+ for (index, existing) in self.keys.iter().enumerate() {
+ if *existing == key {
+ return Entry::Occupied(OccupiedEntry { v: self, index });
+ }
+ }
+ Entry::Vacant(VacantEntry { v: self, key })
+ }
+
+ pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
+ where
+ K: Borrow<Q>,
+ Q: Eq,
+ {
+ for (index, existing) in self.keys.iter().enumerate() {
+ if existing.borrow() == k {
+ return Some(&self.values[index]);
+ }
+ }
+ None
+ }
+
+ pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
+ where
+ K: Borrow<Q>,
+ Q: Eq,
+ {
+ for (index, existing) in self.keys.iter().enumerate() {
+ if existing.borrow() == k {
+ return Some(&mut self.values[index]);
+ }
+ }
+ None
+ }
+
+ pub fn keys(&self) -> std::slice::Iter<'_, K> {
+ self.keys.iter()
+ }
+
+ pub fn iter(&self) -> Iter<K, V> {
+ Iter {
+ keys: self.keys.iter(),
+ values: self.values.iter(),
+ }
+ }
+
+ pub fn iter_mut(&mut self) -> IterMut<K, V> {
+ IterMut {
+ keys: self.keys.iter_mut(),
+ values: self.values.iter_mut(),
+ }
+ }
+}
+
+impl<K: PartialEq + Eq, V> Default for FlatMap<K, V> {
+ fn default() -> Self {
+ Self {
+ keys: Default::default(),
+ values: Default::default(),
+ }
+ }
+}
+
+pub enum Entry<'a, K: 'a, V: 'a> {
+ Vacant(VacantEntry<'a, K, V>),
+ Occupied(OccupiedEntry<'a, K, V>),
+}
+
+impl<'a, K: 'a, V: 'a> Entry<'a, K, V> {
+ pub fn or_insert(self, default: V) -> &'a mut V {
+ match self {
+ Entry::Occupied(entry) => &mut entry.v.values[entry.index],
+ Entry::Vacant(entry) => {
+ entry.v.keys.push(entry.key);
+ entry.v.values.push(default);
+ entry.v.values.last_mut().unwrap()
+ }
+ }
+ }
+
+ pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
+ match self {
+ Entry::Occupied(entry) => &mut entry.v.values[entry.index],
+ Entry::Vacant(entry) => {
+ entry.v.keys.push(entry.key);
+ entry.v.values.push(default());
+ entry.v.values.last_mut().unwrap()
+ }
+ }
+ }
+}
+
+pub struct VacantEntry<'a, K: 'a, V: 'a> {
+ v: &'a mut FlatMap<K, V>,
+ key: K,
+}
+
+pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
+ v: &'a mut FlatMap<K, V>,
+ index: usize,
+}
+
+pub struct Iter<'a, K: 'a, V: 'a> {
+ keys: std::slice::Iter<'a, K>,
+ values: std::slice::Iter<'a, V>,
+}
+
+impl<'a, K, V> Iterator for Iter<'a, K, V> {
+ type Item = (&'a K, &'a V);
+
+ fn next(&mut self) -> Option<(&'a K, &'a V)> {
+ match self.keys.next() {
+ Some(k) => {
+ let v = self.values.next().unwrap();
+ Some((k, v))
+ }
+ None => None,
+ }
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.keys.size_hint()
+ }
+}
+
+impl<'a, K, V> DoubleEndedIterator for Iter<'a, K, V> {
+ fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
+ match self.keys.next_back() {
+ Some(k) => {
+ let v = self.values.next_back().unwrap();
+ Some((k, v))
+ }
+ None => None,
+ }
+ }
+}
+
+impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {}
+
+pub struct IterMut<'a, K: 'a, V: 'a> {
+ keys: std::slice::IterMut<'a, K>,
+ values: std::slice::IterMut<'a, V>,
+}
+
+impl<'a, K, V> Iterator for IterMut<'a, K, V> {
+ type Item = (&'a K, &'a mut V);
+
+ fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
+ match self.keys.next() {
+ Some(k) => {
+ let v = self.values.next().unwrap();
+ Some((k, v))
+ }
+ None => None,
+ }
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.keys.size_hint()
+ }
+}
+
+impl<'a, K, V> DoubleEndedIterator for IterMut<'a, K, V> {
+ fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> {
+ match self.keys.next_back() {
+ Some(k) => {
+ let v = self.values.next_back().unwrap();
+ Some((k, v))
+ }
+ None => None,
+ }
+ }
+}
+
+impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {}
diff --git a/third_party/rust/clap_builder/src/util/flat_set.rs b/third_party/rust/clap_builder/src/util/flat_set.rs
new file mode 100644
index 0000000000..3e0b23dae3
--- /dev/null
+++ b/third_party/rust/clap_builder/src/util/flat_set.rs
@@ -0,0 +1,107 @@
+#![allow(dead_code)]
+
+use std::borrow::Borrow;
+
+/// Flat (Vec) backed set
+///
+/// This preserves insertion order
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub(crate) struct FlatSet<T> {
+ inner: Vec<T>,
+}
+
+impl<T: PartialEq + Eq> FlatSet<T> {
+ pub(crate) fn new() -> Self {
+ Default::default()
+ }
+
+ pub(crate) fn insert(&mut self, value: T) -> bool {
+ for existing in &self.inner {
+ if *existing == value {
+ return false;
+ }
+ }
+ self.inner.push(value);
+ true
+ }
+
+ pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool
+ where
+ T: Borrow<Q>,
+ Q: Eq,
+ {
+ for existing in &self.inner {
+ if existing.borrow() == value {
+ return true;
+ }
+ }
+ false
+ }
+
+ pub fn retain<F>(&mut self, f: F)
+ where
+ F: FnMut(&T) -> bool,
+ {
+ self.inner.retain(f);
+ }
+
+ pub(crate) fn is_empty(&self) -> bool {
+ self.inner.is_empty()
+ }
+
+ pub(crate) fn iter(&self) -> std::slice::Iter<'_, T> {
+ self.inner.iter()
+ }
+
+ pub fn sort_by_key<K, F>(&mut self, f: F)
+ where
+ F: FnMut(&T) -> K,
+ K: Ord,
+ {
+ self.inner.sort_by_key(f);
+ }
+}
+
+impl<T: PartialEq + Eq> Default for FlatSet<T> {
+ fn default() -> Self {
+ Self {
+ inner: Default::default(),
+ }
+ }
+}
+
+impl<T: PartialEq + Eq> IntoIterator for FlatSet<T> {
+ type Item = T;
+ type IntoIter = std::vec::IntoIter<T>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.inner.into_iter()
+ }
+}
+
+impl<'s, T: PartialEq + Eq> IntoIterator for &'s FlatSet<T> {
+ type Item = &'s T;
+ type IntoIter = std::slice::Iter<'s, T>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.inner.iter()
+ }
+}
+
+impl<T: PartialEq + Eq> Extend<T> for FlatSet<T> {
+ fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+ for value in iter {
+ self.insert(value);
+ }
+ }
+}
+
+impl<T: PartialEq + Eq> FromIterator<T> for FlatSet<T> {
+ fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
+ let mut set = Self::new();
+ for value in iter {
+ set.insert(value);
+ }
+ set
+ }
+}
diff --git a/third_party/rust/clap_builder/src/util/graph.rs b/third_party/rust/clap_builder/src/util/graph.rs
new file mode 100644
index 0000000000..d646400b01
--- /dev/null
+++ b/third_party/rust/clap_builder/src/util/graph.rs
@@ -0,0 +1,49 @@
+#[derive(Debug)]
+struct Child<T> {
+ id: T,
+ children: Vec<usize>,
+}
+
+impl<T> Child<T> {
+ fn new(id: T) -> Self {
+ Child {
+ id,
+ children: vec![],
+ }
+ }
+}
+
+#[derive(Debug)]
+pub(crate) struct ChildGraph<T>(Vec<Child<T>>);
+
+impl<T> ChildGraph<T>
+where
+ T: Sized + PartialEq + Clone,
+{
+ pub(crate) fn with_capacity(s: usize) -> Self {
+ ChildGraph(Vec::with_capacity(s))
+ }
+
+ pub(crate) fn insert(&mut self, req: T) -> usize {
+ self.0.iter().position(|e| e.id == req).unwrap_or_else(|| {
+ let idx = self.0.len();
+ self.0.push(Child::new(req));
+ idx
+ })
+ }
+
+ pub(crate) fn insert_child(&mut self, parent: usize, child: T) -> usize {
+ let c_idx = self.0.len();
+ self.0.push(Child::new(child));
+ self.0[parent].children.push(c_idx);
+ c_idx
+ }
+
+ pub(crate) fn iter(&self) -> impl Iterator<Item = &T> {
+ self.0.iter().map(|r| &r.id)
+ }
+
+ pub(crate) fn contains(&self, req: &T) -> bool {
+ self.0.iter().any(|r| r.id == *req)
+ }
+}
diff --git a/third_party/rust/clap_builder/src/util/id.rs b/third_party/rust/clap_builder/src/util/id.rs
new file mode 100644
index 0000000000..710d2ea7d1
--- /dev/null
+++ b/third_party/rust/clap_builder/src/util/id.rs
@@ -0,0 +1,164 @@
+use crate::builder::Str;
+
+/// [`Arg`][crate::Arg] or [`ArgGroup`][crate::ArgGroup] identifier
+///
+/// This is used for accessing the value in [`ArgMatches`][crate::ArgMatches] or defining
+/// relationships between `Arg`s and `ArgGroup`s with functions like
+/// [`Arg::conflicts_with`][crate::Arg::conflicts_with].
+#[derive(Default, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
+pub struct Id(Str);
+
+impl Id {
+ pub(crate) const HELP: &'static str = "help";
+ pub(crate) const VERSION: &'static str = "version";
+ pub(crate) const EXTERNAL: &'static str = "";
+
+ pub(crate) fn from_static_ref(name: &'static str) -> Self {
+ Self(Str::from_static_ref(name))
+ }
+
+ /// Get the raw string of the `Id`
+ pub fn as_str(&self) -> &str {
+ self.0.as_str()
+ }
+
+ pub(crate) fn as_internal_str(&self) -> &Str {
+ &self.0
+ }
+}
+
+impl From<&'_ Id> for Id {
+ fn from(id: &'_ Id) -> Self {
+ id.clone()
+ }
+}
+
+impl From<Str> for Id {
+ fn from(name: Str) -> Self {
+ Self(name)
+ }
+}
+
+impl From<&'_ Str> for Id {
+ fn from(name: &'_ Str) -> Self {
+ Self(name.into())
+ }
+}
+
+#[cfg(feature = "string")]
+impl From<std::string::String> for Id {
+ fn from(name: std::string::String) -> Self {
+ Self(name.into())
+ }
+}
+
+#[cfg(feature = "string")]
+impl From<&'_ std::string::String> for Id {
+ fn from(name: &'_ std::string::String) -> Self {
+ Self(name.into())
+ }
+}
+
+impl From<&'static str> for Id {
+ fn from(name: &'static str) -> Self {
+ Self(name.into())
+ }
+}
+
+impl From<&'_ &'static str> for Id {
+ fn from(name: &'_ &'static str) -> Self {
+ Self(name.into())
+ }
+}
+
+impl From<Id> for Str {
+ fn from(name: Id) -> Self {
+ name.0
+ }
+}
+
+impl From<Id> for String {
+ fn from(name: Id) -> Self {
+ Str::from(name).into()
+ }
+}
+
+impl std::fmt::Display for Id {
+ #[inline]
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.as_str(), f)
+ }
+}
+
+impl std::fmt::Debug for Id {
+ #[inline]
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Debug::fmt(self.as_str(), f)
+ }
+}
+
+impl AsRef<str> for Id {
+ #[inline]
+ fn as_ref(&self) -> &str {
+ self.as_str()
+ }
+}
+
+impl std::borrow::Borrow<str> for Id {
+ #[inline]
+ fn borrow(&self) -> &str {
+ self.as_str()
+ }
+}
+
+impl PartialEq<str> for Id {
+ #[inline]
+ fn eq(&self, other: &str) -> bool {
+ PartialEq::eq(self.as_str(), other)
+ }
+}
+impl PartialEq<Id> for str {
+ #[inline]
+ fn eq(&self, other: &Id) -> bool {
+ PartialEq::eq(self, other.as_str())
+ }
+}
+
+impl PartialEq<&'_ str> for Id {
+ #[inline]
+ fn eq(&self, other: &&str) -> bool {
+ PartialEq::eq(self.as_str(), *other)
+ }
+}
+impl PartialEq<Id> for &'_ str {
+ #[inline]
+ fn eq(&self, other: &Id) -> bool {
+ PartialEq::eq(*self, other.as_str())
+ }
+}
+
+impl PartialEq<Str> for Id {
+ #[inline]
+ fn eq(&self, other: &Str) -> bool {
+ PartialEq::eq(self.as_str(), other.as_str())
+ }
+}
+impl PartialEq<Id> for Str {
+ #[inline]
+ fn eq(&self, other: &Id) -> bool {
+ PartialEq::eq(self.as_str(), other.as_str())
+ }
+}
+
+impl PartialEq<std::string::String> for Id {
+ #[inline]
+ fn eq(&self, other: &std::string::String) -> bool {
+ PartialEq::eq(self.as_str(), other.as_str())
+ }
+}
+impl PartialEq<Id> for std::string::String {
+ #[inline]
+ fn eq(&self, other: &Id) -> bool {
+ PartialEq::eq(other, self)
+ }
+}
diff --git a/third_party/rust/clap_builder/src/util/mod.rs b/third_party/rust/clap_builder/src/util/mod.rs
new file mode 100644
index 0000000000..a92aef8c3e
--- /dev/null
+++ b/third_party/rust/clap_builder/src/util/mod.rs
@@ -0,0 +1,47 @@
+#![allow(clippy::single_component_path_imports)]
+
+mod any_value;
+pub(crate) mod flat_map;
+pub(crate) mod flat_set;
+mod graph;
+mod id;
+mod str_to_bool;
+
+pub use self::id::Id;
+
+pub(crate) use self::any_value::AnyValue;
+pub(crate) use self::any_value::AnyValueId;
+pub(crate) use self::flat_map::Entry;
+pub(crate) use self::flat_map::FlatMap;
+pub(crate) use self::flat_set::FlatSet;
+pub(crate) use self::graph::ChildGraph;
+pub(crate) use self::str_to_bool::str_to_bool;
+pub(crate) use self::str_to_bool::FALSE_LITERALS;
+pub(crate) use self::str_to_bool::TRUE_LITERALS;
+
+pub(crate) mod color;
+
+pub(crate) const SUCCESS_CODE: i32 = 0;
+// While sysexists.h defines EX_USAGE as 64, this doesn't seem to be used much in practice but
+// instead 2 seems to be frequently used.
+// Examples
+// - GNU `ls` returns 2
+// - Python's `argparse` returns 2
+pub(crate) const USAGE_CODE: i32 = 2;
+
+pub(crate) fn safe_exit(code: i32) -> ! {
+ use std::io::Write;
+
+ let _ = std::io::stdout().lock().flush();
+ let _ = std::io::stderr().lock().flush();
+
+ std::process::exit(code)
+}
+
+#[cfg(not(feature = "unicode"))]
+pub(crate) fn eq_ignore_case(left: &str, right: &str) -> bool {
+ left.eq_ignore_ascii_case(right)
+}
+
+#[cfg(feature = "unicode")]
+pub(crate) use unicase::eq as eq_ignore_case;
diff --git a/third_party/rust/clap_builder/src/util/str_to_bool.rs b/third_party/rust/clap_builder/src/util/str_to_bool.rs
new file mode 100644
index 0000000000..1fbdc7531a
--- /dev/null
+++ b/third_party/rust/clap_builder/src/util/str_to_bool.rs
@@ -0,0 +1,21 @@
+/// True values are `y`, `yes`, `t`, `true`, `on`, and `1`.
+pub(crate) const TRUE_LITERALS: [&str; 6] = ["y", "yes", "t", "true", "on", "1"];
+
+/// False values are `n`, `no`, `f`, `false`, `off`, and `0`.
+pub(crate) const FALSE_LITERALS: [&str; 6] = ["n", "no", "f", "false", "off", "0"];
+
+/// Converts a string literal representation of truth to true or false.
+///
+/// `false` values are `n`, `no`, `f`, `false`, `off`, and `0` (case insensitive).
+///
+/// Any other value will be considered as `true`.
+pub(crate) fn str_to_bool(val: impl AsRef<str>) -> Option<bool> {
+ let pat: &str = &val.as_ref().to_lowercase();
+ if TRUE_LITERALS.contains(&pat) {
+ Some(true)
+ } else if FALSE_LITERALS.contains(&pat) {
+ Some(false)
+ } else {
+ None
+ }
+}