aboutsummaryrefslogtreecommitdiff
path: root/arg_picker/src
diff options
context:
space:
mode:
Diffstat (limited to 'arg_picker/src')
-rw-r--r--arg_picker/src/arg.rs18
-rw-r--r--arg_picker/src/builtin.rs4
-rw-r--r--arg_picker/src/builtin/pick_ip_attr.rs39
-rw-r--r--arg_picker/src/builtin/pick_pathbuf.rs18
-rw-r--r--arg_picker/src/builtin/pick_paths.rs167
-rw-r--r--arg_picker/src/builtin/pick_socket_attr.rs39
-rw-r--r--arg_picker/src/corebind.rs2
-rw-r--r--arg_picker/src/picker/parse.rs49
-rw-r--r--arg_picker/src/picker/result.rs49
-rw-r--r--arg_picker/src/value.rs3
-rw-r--r--arg_picker/src/value/paths.rs294
11 files changed, 679 insertions, 3 deletions
diff --git a/arg_picker/src/arg.rs b/arg_picker/src/arg.rs
index 4fa21b5..0b5176d 100644
--- a/arg_picker/src/arg.rs
+++ b/arg_picker/src/arg.rs
@@ -1,4 +1,4 @@
-use crate::{Pickable, PickerArgInfo};
+use crate::{Pickable, PickerArgInfo, SinglePickable, parselib::ParserStyle};
use std::marker::PhantomData;
/// Represents a constraint definition for a parameter selection.
@@ -164,6 +164,22 @@ where
}
}
+impl<'a, Type> From<PickerArg<'a, Type>> for Vec<String>
+where
+ Type: SinglePickable,
+{
+ fn from(value: PickerArg<'a, Type>) -> Self {
+ let mut result = Vec::new();
+ let info = PickerArgInfo::from(value);
+ let possible_flags =
+ crate::parselib::build_possible_flags(ParserStyle::global_style(), &info);
+ for flag in possible_flags {
+ result.push(flag);
+ }
+ result
+ }
+}
+
/// Describes the attribute (behavior) of a command-line parameter.
///
/// The ordering reflects parse priority (higher = parsed first):
diff --git a/arg_picker/src/builtin.rs b/arg_picker/src/builtin.rs
index 1c698ba..76c0645 100644
--- a/arg_picker/src/builtin.rs
+++ b/arg_picker/src/builtin.rs
@@ -1,5 +1,9 @@
mod pick_bool;
mod pick_flag;
+mod pick_ip_attr;
mod pick_numbers;
+mod pick_pathbuf;
+mod pick_paths;
mod pick_picker_args;
+mod pick_socket_attr;
mod pick_string;
diff --git a/arg_picker/src/builtin/pick_ip_attr.rs b/arg_picker/src/builtin/pick_ip_attr.rs
new file mode 100644
index 0000000..d68fa15
--- /dev/null
+++ b/arg_picker/src/builtin/pick_ip_attr.rs
@@ -0,0 +1,39 @@
+use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+
+use crate::SinglePickable;
+
+impl SinglePickable for IpAddr {
+ fn pick_single(str: Option<&str>) -> crate::PickerArgResult<Self> {
+ match str {
+ Some(s) => match s.parse::<IpAddr>() {
+ Ok(addr) => crate::PickerArgResult::Parsed(addr),
+ Err(_) => crate::PickerArgResult::NotFound,
+ },
+ None => crate::PickerArgResult::NotFound,
+ }
+ }
+}
+
+impl SinglePickable for Ipv4Addr {
+ fn pick_single(str: Option<&str>) -> crate::PickerArgResult<Self> {
+ match str {
+ Some(s) => match s.parse::<Ipv4Addr>() {
+ Ok(addr) => crate::PickerArgResult::Parsed(addr),
+ Err(_) => crate::PickerArgResult::NotFound,
+ },
+ None => crate::PickerArgResult::NotFound,
+ }
+ }
+}
+
+impl SinglePickable for Ipv6Addr {
+ fn pick_single(str: Option<&str>) -> crate::PickerArgResult<Self> {
+ match str {
+ Some(s) => match s.parse::<Ipv6Addr>() {
+ Ok(addr) => crate::PickerArgResult::Parsed(addr),
+ Err(_) => crate::PickerArgResult::NotFound,
+ },
+ None => crate::PickerArgResult::NotFound,
+ }
+ }
+}
diff --git a/arg_picker/src/builtin/pick_pathbuf.rs b/arg_picker/src/builtin/pick_pathbuf.rs
new file mode 100644
index 0000000..3bd4410
--- /dev/null
+++ b/arg_picker/src/builtin/pick_pathbuf.rs
@@ -0,0 +1,18 @@
+use std::path::PathBuf;
+
+use crate::{
+ PickerArgResult::{NotFound, Parsed},
+ SinglePickable,
+};
+
+impl SinglePickable for PathBuf {
+ fn pick_single(str: Option<&str>) -> crate::PickerArgResult<Self> {
+ match str {
+ Some(str) => match just_fmt::fmt_path_str(str) {
+ Ok(formated) => Parsed(PathBuf::from(formated)),
+ Err(_) => NotFound,
+ },
+ None => NotFound,
+ }
+ }
+}
diff --git a/arg_picker/src/builtin/pick_paths.rs b/arg_picker/src/builtin/pick_paths.rs
new file mode 100644
index 0000000..8e6c0fd
--- /dev/null
+++ b/arg_picker/src/builtin/pick_paths.rs
@@ -0,0 +1,167 @@
+use std::{
+ fs,
+ path::{Path, PathBuf},
+};
+
+use crate::{
+ PickerArgResult::{self, NotFound, Parsed, Unparsed},
+ SinglePickable,
+ value::{
+ DirPath, FilePath, NoDirPath, NoFilePath, NoPath, NoSymlinkPath, RecursiveFiles,
+ SymlinkPath,
+ },
+};
+
+impl SinglePickable for FilePath {
+ fn pick_single(str: Option<&str>) -> PickerArgResult<Self> {
+ match <PathBuf as SinglePickable>::pick_single(str) {
+ Parsed(path) => {
+ if path.exists() && path.is_file() {
+ Parsed(FilePath::from(path))
+ } else {
+ NotFound
+ }
+ }
+ Unparsed => Unparsed,
+ NotFound => NotFound,
+ }
+ }
+}
+
+impl SinglePickable for NoFilePath {
+ fn pick_single(str: Option<&str>) -> PickerArgResult<Self> {
+ match <PathBuf as SinglePickable>::pick_single(str) {
+ Parsed(path) => {
+ if !path.exists() || !path.is_file() {
+ Parsed(NoFilePath::from(path))
+ } else {
+ NotFound
+ }
+ }
+ Unparsed => Unparsed,
+ NotFound => NotFound,
+ }
+ }
+}
+
+impl SinglePickable for DirPath {
+ fn pick_single(str: Option<&str>) -> PickerArgResult<Self> {
+ match <PathBuf as SinglePickable>::pick_single(str) {
+ Parsed(path) => {
+ if path.exists() && path.is_dir() {
+ Parsed(DirPath::from(path))
+ } else {
+ NotFound
+ }
+ }
+ Unparsed => Unparsed,
+ NotFound => NotFound,
+ }
+ }
+}
+
+impl SinglePickable for NoDirPath {
+ fn pick_single(str: Option<&str>) -> PickerArgResult<Self> {
+ match <PathBuf as SinglePickable>::pick_single(str) {
+ Parsed(path) => {
+ if !path.exists() || !path.is_dir() {
+ Parsed(NoDirPath::from(path))
+ } else {
+ NotFound
+ }
+ }
+ Unparsed => Unparsed,
+ NotFound => NotFound,
+ }
+ }
+}
+
+impl SinglePickable for SymlinkPath {
+ fn pick_single(str: Option<&str>) -> PickerArgResult<Self> {
+ match <PathBuf as SinglePickable>::pick_single(str) {
+ Parsed(path) => {
+ if path.exists() && path.is_symlink() {
+ Parsed(SymlinkPath::from(path))
+ } else {
+ NotFound
+ }
+ }
+ Unparsed => Unparsed,
+ NotFound => NotFound,
+ }
+ }
+}
+
+impl SinglePickable for NoSymlinkPath {
+ fn pick_single(str: Option<&str>) -> PickerArgResult<Self> {
+ match <PathBuf as SinglePickable>::pick_single(str) {
+ Parsed(path) => {
+ if !path.exists() || !path.is_symlink() {
+ Parsed(NoSymlinkPath::from(path))
+ } else {
+ NotFound
+ }
+ }
+ Unparsed => Unparsed,
+ NotFound => NotFound,
+ }
+ }
+}
+
+impl SinglePickable for NoPath {
+ fn pick_single(str: Option<&str>) -> PickerArgResult<Self> {
+ match <PathBuf as SinglePickable>::pick_single(str) {
+ Parsed(path) => {
+ if !path.exists() {
+ Parsed(NoPath::from(path))
+ } else {
+ NotFound
+ }
+ }
+ Unparsed => Unparsed,
+ NotFound => NotFound,
+ }
+ }
+}
+
+impl SinglePickable for RecursiveFiles {
+ fn pick_single(str: Option<&str>) -> PickerArgResult<Self> {
+ match <PathBuf as SinglePickable>::pick_single(str) {
+ Parsed(path) => {
+ if !path.exists() {
+ return NotFound;
+ }
+ if path.is_file() || path.is_symlink() {
+ return Parsed(RecursiveFiles::from(vec![path]));
+ }
+ let mut entries = Vec::new();
+ if let Ok(dir_entries) = fs::read_dir(&path) {
+ for entry in dir_entries.flatten() {
+ let entry_path = entry.path();
+ if entry_path.is_file() || entry_path.is_symlink() {
+ entries.push(entry_path);
+ } else if entry_path.is_dir() {
+ collect_files(&entry_path, &mut entries);
+ }
+ }
+ }
+ Parsed(RecursiveFiles::from(entries))
+ }
+ Unparsed => Unparsed,
+ NotFound => NotFound,
+ }
+ }
+}
+
+fn collect_files(dir: &Path, entries: &mut Vec<PathBuf>) {
+ if let Ok(dir_entries) = fs::read_dir(dir) {
+ for entry in dir_entries.flatten() {
+ let entry_path = entry.path();
+ if entry_path.is_file() || entry_path.is_symlink() {
+ entries.push(entry_path);
+ } else if entry_path.is_dir() {
+ collect_files(&entry_path, entries);
+ }
+ }
+ }
+}
diff --git a/arg_picker/src/builtin/pick_socket_attr.rs b/arg_picker/src/builtin/pick_socket_attr.rs
new file mode 100644
index 0000000..0c0dd71
--- /dev/null
+++ b/arg_picker/src/builtin/pick_socket_attr.rs
@@ -0,0 +1,39 @@
+use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
+
+use crate::SinglePickable;
+
+impl SinglePickable for SocketAddr {
+ fn pick_single(str: Option<&str>) -> crate::PickerArgResult<Self> {
+ match str {
+ Some(s) => match s.parse::<SocketAddr>() {
+ Ok(addr) => crate::PickerArgResult::Parsed(addr),
+ Err(_) => crate::PickerArgResult::NotFound,
+ },
+ None => crate::PickerArgResult::NotFound,
+ }
+ }
+}
+
+impl SinglePickable for SocketAddrV4 {
+ fn pick_single(str: Option<&str>) -> crate::PickerArgResult<Self> {
+ match str {
+ Some(s) => match s.parse::<SocketAddrV4>() {
+ Ok(addr) => crate::PickerArgResult::Parsed(addr),
+ Err(_) => crate::PickerArgResult::NotFound,
+ },
+ None => crate::PickerArgResult::NotFound,
+ }
+ }
+}
+
+impl SinglePickable for SocketAddrV6 {
+ fn pick_single(str: Option<&str>) -> crate::PickerArgResult<Self> {
+ match str {
+ Some(s) => match s.parse::<SocketAddrV6>() {
+ Ok(addr) => crate::PickerArgResult::Parsed(addr),
+ Err(_) => crate::PickerArgResult::NotFound,
+ },
+ None => crate::PickerArgResult::NotFound,
+ }
+ }
+}
diff --git a/arg_picker/src/corebind.rs b/arg_picker/src/corebind.rs
deleted file mode 100644
index 3581871..0000000
--- a/arg_picker/src/corebind.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-mod entry_picker;
-pub use entry_picker::*;
diff --git a/arg_picker/src/picker/parse.rs b/arg_picker/src/picker/parse.rs
index 9db5bd9..4a959e3 100644
--- a/arg_picker/src/picker/parse.rs
+++ b/arg_picker/src/picker/parse.rs
@@ -33,6 +33,55 @@ internal_repeat!(1..=32 => {
((p.v$.expect(concat!("missing required argument at position ", $)),+))
}
+ /// Returns the parsed values, using the default values for any missing
+ /// required arguments, or panicking if a route was selected.
+ ///
+ /// # Panics
+ ///
+ /// Panics if a route was selected.
+ ///
+ /// # Type Constraints
+ ///
+ /// All types in the tuple must implement [`Default`].
+ pub fn unwrap_or_default(self) -> ((T$,+))
+ where
+ (
+ T$: Default,
+ +) {
+ let p = self.parse();
+ ((p.v$.unwrap_or_default(),+))
+ }
+
+ /// Returns the parsed values, using the provided closure to generate
+ /// default values for any missing required arguments, or panicking if
+ /// a route was selected.
+ ///
+ /// # Panics
+ ///
+ /// Panics if a route was selected.
+ pub fn unwrap_or_else<F>(self, op: F) -> ((T$,+))
+ where
+ F: FnOnce(Route) -> ((T$,+)),
+ {
+ let r = self.to_result();
+ r.unwrap_or_else(op)
+ }
+
+ /// Returns the parsed values, or panics with the given message if
+ /// a route was selected.
+ ///
+ /// # Panics
+ ///
+ /// Panics if a route was selected, with the provided message.
+ ///
+ /// # Type Constraints
+ ///
+ /// `Route` must implement [`std::fmt::Debug`] so that the error
+ /// message can include the route value.
+ pub fn expect(self, msg: &str) -> ((T$,+)) where Route: std::fmt::Debug {
+ self.to_result().expect(msg)
+ }
+
/// Returns the individual option values without checking the route.
pub fn unpack(self) -> ((Option<T$>,+)) {
let p = self.parse();
diff --git a/arg_picker/src/picker/result.rs b/arg_picker/src/picker/result.rs
index 2099825..f13f52e 100644
--- a/arg_picker/src/picker/result.rs
+++ b/arg_picker/src/picker/result.rs
@@ -32,6 +32,55 @@ internal_repeat!(1..=32 => {
((self.v$.expect(concat!("missing required argument at position ", $)),+))
}
+ /// Returns the parsed values, using the default values for any missing
+ /// required arguments, or panicking if a route was selected.
+ ///
+ /// # Panics
+ ///
+ /// Panics if a route was selected.
+ ///
+ /// # Type Constraints
+ ///
+ /// All types in the tuple must implement [`Default`].
+ pub fn unwrap_or_default(self) -> ((T$,+))
+ where
+ (
+ T$: Default,
+ +) {
+ let p = self;
+ ((p.v$.unwrap_or_default(),+))
+ }
+
+ /// Returns the parsed values, using the provided closure to generate
+ /// default values for any missing required arguments, or panicking if
+ /// a route was selected.
+ ///
+ /// # Panics
+ ///
+ /// Panics if a route was selected.
+ pub fn unwrap_or_else<F>(self, op: F) -> ((T$,+))
+ where
+ F: FnOnce(Route) -> ((T$,+)),
+ {
+ let r = self.to_result();
+ r.unwrap_or_else(op)
+ }
+
+ /// Returns the parsed values, or panics with the given message if
+ /// a route was selected.
+ ///
+ /// # Panics
+ ///
+ /// Panics if a route was selected, with the provided message.
+ ///
+ /// # Type Constraints
+ ///
+ /// `Route` must implement [`std::fmt::Debug`] so that the error
+ /// message can include the route value.
+ pub fn expect(self, msg: &str) -> ((T$,+)) where Route: std::fmt::Debug {
+ self.to_result().expect(msg)
+ }
+
/// Returns the individual option values without checking the route.
pub fn unpack(self) -> ((Option<T$>,+)) {
((self.v$,+))
diff --git a/arg_picker/src/value.rs b/arg_picker/src/value.rs
index 995aa00..04d3e01 100644
--- a/arg_picker/src/value.rs
+++ b/arg_picker/src/value.rs
@@ -1,5 +1,8 @@
mod flag;
pub use flag::*;
+mod paths;
+pub use paths::*;
+
mod vec_until;
pub use vec_until::*;
diff --git a/arg_picker/src/value/paths.rs b/arg_picker/src/value/paths.rs
new file mode 100644
index 0000000..403d6cc
--- /dev/null
+++ b/arg_picker/src/value/paths.rs
@@ -0,0 +1,294 @@
+use std::{
+ ops::{Deref, DerefMut},
+ path::{Path, PathBuf},
+};
+
+/// A file path.
+///
+/// `FilePath` is a wrapper type around `PathBuf` representing an arbitrary file path.
+///
+/// It implements `Pickable` and can be parsed by a `Picker`.
+///
+/// # Parsing Behavior
+///
+/// At the moment of parsing, checks whether the path exists and is a file.
+/// If not a file, returns `NotFound`.
+#[non_exhaustive]
+pub struct FilePath {
+ path: PathBuf,
+}
+
+/// A file path that should not exist.
+///
+/// `NoFilePath` is a wrapper type around `PathBuf` representing an arbitrary path
+/// that must not currently point to an existing file.
+///
+/// It implements `Pickable` and can be parsed by a `Picker`.
+///
+/// # Parsing Behavior
+///
+/// At the moment of parsing, checks whether no file exists at the given path.
+/// If a file already exists (regardless of whether it is a regular file, directory,
+/// symlink, or other type), returns `NotFound`.
+#[non_exhaustive]
+pub struct NoFilePath {
+ path: PathBuf,
+}
+
+/// A directory path.
+///
+/// `DirPath` is a wrapper type around `PathBuf` representing an arbitrary existing
+/// directory path.
+///
+/// It implements `Pickable` and can be parsed by a `Picker`.
+///
+/// # Parsing Behavior
+///
+/// At the moment of parsing, checks whether a directory exists at the given path.
+/// If no directory exists, returns `NotFound`.
+#[non_exhaustive]
+pub struct DirPath {
+ path: PathBuf,
+}
+
+/// A directory path that should not exist.
+///
+/// `NoDirPath` is a wrapper type around `PathBuf` representing an arbitrary path
+/// that must not currently point to an existing directory.
+///
+/// It implements `Pickable` and can be parsed by a `Picker`.
+///
+/// # Parsing Behavior
+///
+/// At the moment of parsing, checks whether no directory exists at the given path.
+/// If a directory already exists (regardless of whether it is a regular file, file,
+/// symlink, or other type), returns `NotFound`.
+#[non_exhaustive]
+pub struct NoDirPath {
+ path: PathBuf,
+}
+
+/// A symbolic link path.
+///
+/// `SymlinkPath` is a wrapper type around `PathBuf` representing an existing symbolic link.
+///
+/// It implements `Pickable` and can be parsed by a `Picker`.
+///
+/// # Parsing Behavior
+///
+/// At the moment of parsing, checks whether the path exists and is a symlink.
+/// If not a symlink, returns `NotFound`.
+#[non_exhaustive]
+pub struct SymlinkPath {
+ path: PathBuf,
+}
+
+/// A symbolic link path that should not exist.
+///
+/// `NoSymlinkPath` is a wrapper type around `PathBuf` representing an arbitrary path
+/// that must not currently point to an existing symbolic link.
+///
+/// It implements `Pickable` and can be parsed by a `Picker`.
+///
+/// # Parsing Behavior
+///
+/// At the moment of parsing, checks whether no symlink exists at the given path.
+/// If a symlink already exists (regardless of whether it points to a file, directory,
+/// or other type), returns `NotFound`.
+#[non_exhaustive]
+pub struct NoSymlinkPath {
+ path: PathBuf,
+}
+
+/// A path that should not exist at all.
+///
+/// `NoPath` is a wrapper type around `PathBuf` representing an arbitrary path
+/// that must not currently exist on the filesystem (as a file, directory, symlink,
+/// or any other type).
+///
+/// It implements `Pickable` and can be parsed by a `Picker`.
+///
+/// # Parsing Behavior
+///
+/// At the moment of parsing, checks whether any filesystem entry exists at the given path.
+/// If anything exists at that path, returns `NotFound`.
+#[non_exhaustive]
+pub struct NoPath {
+ path: PathBuf,
+}
+
+/// Implements common trait impls (From, AsRef, Deref, DerefMut) for a path wrapper type.
+macro_rules! impl_path_traits {
+ ($type:ident) => {
+ impl From<PathBuf> for $type {
+ fn from(value: PathBuf) -> Self {
+ $type { path: value }
+ }
+ }
+
+ impl From<&PathBuf> for $type {
+ fn from(value: &PathBuf) -> Self {
+ $type {
+ path: value.clone(),
+ }
+ }
+ }
+
+ impl AsRef<Path> for $type {
+ fn as_ref(&self) -> &Path {
+ &self.path
+ }
+ }
+
+ impl DerefMut for $type {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.path
+ }
+ }
+
+ impl Deref for $type {
+ type Target = PathBuf;
+
+ fn deref(&self) -> &Self::Target {
+ &self.path
+ }
+ }
+
+ impl From<$type> for PathBuf {
+ fn from(value: $type) -> Self {
+ value.path
+ }
+ }
+
+ impl From<&$type> for PathBuf {
+ fn from(value: &$type) -> Self {
+ value.path.clone()
+ }
+ }
+ };
+}
+
+impl_path_traits!(FilePath);
+impl_path_traits!(NoFilePath);
+impl_path_traits!(DirPath);
+impl_path_traits!(NoDirPath);
+impl_path_traits!(SymlinkPath);
+impl_path_traits!(NoSymlinkPath);
+impl_path_traits!(NoPath);
+
+/// Recursive file paths.
+///
+/// `RecursiveFiles` is a wrapper type around `Vec<PathBuf>` representing a list of
+/// existing files.
+///
+/// It implements `Pickable` and can be parsed by a `Picker`.
+///
+/// # Parsing Behavior
+///
+/// - If a file path is given, returns a list of length 1 containing that file.
+/// - If a directory path is given, recursively collects all files under that directory
+/// and returns them as a list.
+#[non_exhaustive]
+pub struct RecursiveFiles {
+ paths: Vec<PathBuf>,
+}
+
+impl From<Vec<PathBuf>> for RecursiveFiles {
+ fn from(paths: Vec<PathBuf>) -> Self {
+ Self { paths }
+ }
+}
+
+impl From<RecursiveFiles> for Vec<PathBuf> {
+ fn from(value: RecursiveFiles) -> Self {
+ value.paths
+ }
+}
+
+impl AsRef<[PathBuf]> for RecursiveFiles {
+ fn as_ref(&self) -> &[PathBuf] {
+ &self.paths
+ }
+}
+
+impl Deref for RecursiveFiles {
+ type Target = Vec<PathBuf>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.paths
+ }
+}
+
+impl DerefMut for RecursiveFiles {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.paths
+ }
+}
+
+impl RecursiveFiles {
+ /// Returns the number of file paths.
+ pub fn len(&self) -> usize {
+ self.paths.len()
+ }
+
+ /// Returns `true` if there are no file paths.
+ pub fn is_empty(&self) -> bool {
+ self.paths.is_empty()
+ }
+
+ /// Returns an iterator over the file paths.
+ pub fn iter(&self) -> std::slice::Iter<'_, PathBuf> {
+ self.paths.iter()
+ }
+}
+
+impl From<Vec<RecursiveFiles>> for RecursiveFiles {
+ fn from(value: Vec<RecursiveFiles>) -> Self {
+ Self {
+ paths: value.into_iter().flat_map(|r| r.paths).collect(),
+ }
+ }
+}
+
+/// Trait for types that can be combined into a single `RecursiveFiles`.
+pub trait IntoRecursiveFiles {
+ /// Combines multiple sources of file paths into a single `RecursiveFiles`.
+ fn combine(self) -> RecursiveFiles;
+}
+
+impl<T> IntoRecursiveFiles for Vec<T>
+where
+ T: Into<RecursiveFiles>,
+{
+ fn combine(self) -> RecursiveFiles {
+ self.into_iter()
+ .map(Into::into)
+ .collect::<Vec<RecursiveFiles>>()
+ .into()
+ }
+}
+
+impl<T> IntoRecursiveFiles for &[T]
+where
+ T: Into<RecursiveFiles> + Clone,
+{
+ fn combine(self) -> RecursiveFiles {
+ self.iter()
+ .cloned()
+ .map(Into::into)
+ .collect::<Vec<RecursiveFiles>>()
+ .into()
+ }
+}
+
+impl<T, const N: usize> IntoRecursiveFiles for [T; N]
+where
+ T: Into<RecursiveFiles>,
+{
+ fn combine(self) -> RecursiveFiles {
+ self.into_iter()
+ .map(Into::into)
+ .collect::<Vec<RecursiveFiles>>()
+ .into()
+ }
+}