aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-symfony-console/src/input
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe-symfony-console/src/input')
-rw-r--r--crates/shirabe-symfony-console/src/input/argv_input.rs3
-rw-r--r--crates/shirabe-symfony-console/src/input/array_input.rs3
-rw-r--r--crates/shirabe-symfony-console/src/input/input.rs14
-rw-r--r--crates/shirabe-symfony-console/src/input/input_interface.rs3
-rw-r--r--crates/shirabe-symfony-console/src/input/input_option.rs87
-rw-r--r--crates/shirabe-symfony-console/src/input/string_input.rs3
6 files changed, 103 insertions, 10 deletions
diff --git a/crates/shirabe-symfony-console/src/input/argv_input.rs b/crates/shirabe-symfony-console/src/input/argv_input.rs
index 94e5299d..6138c195 100644
--- a/crates/shirabe-symfony-console/src/input/argv_input.rs
+++ b/crates/shirabe-symfony-console/src/input/argv_input.rs
@@ -4,6 +4,7 @@ use crate::exception::RuntimeException;
use crate::input::Input;
use crate::input::InputDefinition;
use crate::input::InputInterface;
+use crate::input::InputOptionValue;
use crate::input::StreamableInputInterface;
use indexmap::IndexMap;
use shirabe_php_shim::{PhpMixed, php_regex, preg_match};
@@ -593,7 +594,7 @@ impl InputInterface for ArgvInput {
self.inner.get_options()
}
- fn get_option(&self, name: &str) -> anyhow::Result<PhpMixed> {
+ fn get_option(&self, name: &str) -> anyhow::Result<InputOptionValue> {
self.inner.get_option(name)
}
diff --git a/crates/shirabe-symfony-console/src/input/array_input.rs b/crates/shirabe-symfony-console/src/input/array_input.rs
index a032432b..c9bc9dce 100644
--- a/crates/shirabe-symfony-console/src/input/array_input.rs
+++ b/crates/shirabe-symfony-console/src/input/array_input.rs
@@ -5,6 +5,7 @@ use crate::exception::InvalidOptionException;
use crate::input::Input;
use crate::input::InputDefinition;
use crate::input::InputInterface;
+use crate::input::InputOptionValue;
use crate::input::StreamableInputInterface;
use indexmap::IndexMap;
use shirabe_php_shim::PhpMixed;
@@ -336,7 +337,7 @@ impl InputInterface for ArrayInput {
self.inner.get_options()
}
- fn get_option(&self, name: &str) -> anyhow::Result<PhpMixed> {
+ fn get_option(&self, name: &str) -> anyhow::Result<InputOptionValue> {
self.inner.get_option(name)
}
diff --git a/crates/shirabe-symfony-console/src/input/input.rs b/crates/shirabe-symfony-console/src/input/input.rs
index 88bb9f94..795e9c81 100644
--- a/crates/shirabe-symfony-console/src/input/input.rs
+++ b/crates/shirabe-symfony-console/src/input/input.rs
@@ -3,6 +3,7 @@
use crate::exception::InvalidArgumentException;
use crate::exception::RuntimeException;
use crate::input::InputDefinition;
+use crate::input::InputOptionValue;
use indexmap::IndexMap;
use shirabe_php_shim::{PhpMixed, PhpResource, php_regex, preg_is_match};
@@ -156,14 +157,14 @@ impl Input {
)
}
- pub fn get_option(&self, name: &str) -> anyhow::Result<PhpMixed> {
+ pub fn get_option(&self, name: &str) -> anyhow::Result<InputOptionValue> {
if self.definition.has_negation(name) {
let value = self.get_option(&self.definition.negation_to_name(name)?)?;
- if matches!(value, PhpMixed::Null) {
+ if value.is_null() {
return Ok(value);
}
- return Ok(PhpMixed::Bool(!value.as_bool().unwrap_or(false)));
+ return Ok(InputOptionValue::Bool(!value.to_bool()));
}
if !self.definition.has_option(name) {
@@ -174,10 +175,11 @@ impl Input {
.into());
}
- Ok(if self.options.contains_key(name) {
- self.options[name].clone()
+ Ok(if let Some(value) = self.options.get(name) {
+ InputOptionValue::from_php_mixed(value)
} else {
- self.definition.get_option(name)?.get_default().clone()
+ let option = self.definition.get_option(name)?;
+ InputOptionValue::from_php_mixed(option.get_default())
})
}
diff --git a/crates/shirabe-symfony-console/src/input/input_interface.rs b/crates/shirabe-symfony-console/src/input/input_interface.rs
index 4491ca8c..3c3ec2d5 100644
--- a/crates/shirabe-symfony-console/src/input/input_interface.rs
+++ b/crates/shirabe-symfony-console/src/input/input_interface.rs
@@ -1,6 +1,7 @@
//! ref: composer/vendor/symfony/console/Input/InputInterface.php
use crate::input::InputDefinition;
+use crate::input::InputOptionValue;
use crate::input::StreamableInputInterface;
use shirabe_php_shim::PhpMixed;
@@ -33,7 +34,7 @@ pub trait InputInterface: std::fmt::Debug + shirabe_php_shim::AsAny {
fn get_options(&self) -> indexmap::IndexMap<String, PhpMixed>;
- fn get_option(&self, name: &str) -> anyhow::Result<PhpMixed>;
+ fn get_option(&self, name: &str) -> anyhow::Result<InputOptionValue>;
fn set_option(&mut self, name: &str, value: PhpMixed) -> anyhow::Result<()>;
diff --git a/crates/shirabe-symfony-console/src/input/input_option.rs b/crates/shirabe-symfony-console/src/input/input_option.rs
index 3b24d914..d37e18ae 100644
--- a/crates/shirabe-symfony-console/src/input/input_option.rs
+++ b/crates/shirabe-symfony-console/src/input/input_option.rs
@@ -191,3 +191,90 @@ impl InputOption {
&& option.is_value_optional() == self.is_value_optional()
}
}
+
+/// The `bool|string|string[]|null` domain of a parsed option value, as returned by
+/// [`InputInterface::get_option`](crate::input::InputInterface::get_option).
+#[derive(Debug, Clone, PartialEq)]
+pub enum InputOptionValue {
+ Null,
+ Bool(bool),
+ String(String),
+ Array(Vec<String>),
+}
+
+impl InputOptionValue {
+ /// Narrows a raw option value to this domain.
+ ///
+ /// TODO(type-model): `Input` keeps parsed options and `InputOption` defaults as `PhpMixed`, so
+ /// a value outside this domain — an int, a float, or an array holding one — can only be
+ /// rejected here.
+ pub(crate) fn from_php_mixed(value: &PhpMixed) -> Self {
+ match value {
+ PhpMixed::Null => Self::Null,
+ PhpMixed::Bool(b) => Self::Bool(*b),
+ PhpMixed::String(s) => Self::String(s.clone()),
+ PhpMixed::List(_) | PhpMixed::Array(_) => Self::Array(
+ value
+ .values()
+ .into_iter()
+ .map(|item| match item {
+ PhpMixed::String(s) => s.clone(),
+ other => panic!("an option array holds {:?}, not a string", other),
+ })
+ .collect(),
+ ),
+ other => panic!(
+ "an option holds {:?}, not a bool, string, array or null",
+ other
+ ),
+ }
+ }
+
+ pub fn is_null(&self) -> bool {
+ matches!(self, Self::Null)
+ }
+
+ pub fn as_bool(&self) -> Option<bool> {
+ match self {
+ Self::Bool(b) => Some(*b),
+ _ => None,
+ }
+ }
+
+ pub fn as_string(&self) -> Option<&str> {
+ match self {
+ Self::String(s) => Some(s.as_str()),
+ _ => None,
+ }
+ }
+
+ pub fn as_array(&self) -> Option<&[String]> {
+ match self {
+ Self::Array(items) => Some(items),
+ _ => None,
+ }
+ }
+
+ /// PHP loose boolean cast `(bool) $value`.
+ pub fn to_bool(&self) -> bool {
+ match self {
+ Self::Null => false,
+ Self::Bool(b) => *b,
+ Self::String(s) => !s.is_empty() && s != "0",
+ Self::Array(items) => !items.is_empty(),
+ }
+ }
+}
+
+impl From<InputOptionValue> for PhpMixed {
+ fn from(value: InputOptionValue) -> Self {
+ match value {
+ InputOptionValue::Null => PhpMixed::Null,
+ InputOptionValue::Bool(b) => PhpMixed::Bool(b),
+ InputOptionValue::String(s) => PhpMixed::String(s),
+ InputOptionValue::Array(items) => {
+ PhpMixed::List(items.into_iter().map(PhpMixed::String).collect())
+ }
+ }
+ }
+}
diff --git a/crates/shirabe-symfony-console/src/input/string_input.rs b/crates/shirabe-symfony-console/src/input/string_input.rs
index bdd21577..9fcb3fc8 100644
--- a/crates/shirabe-symfony-console/src/input/string_input.rs
+++ b/crates/shirabe-symfony-console/src/input/string_input.rs
@@ -4,6 +4,7 @@ use crate::exception::InvalidArgumentException;
use crate::input::ArgvInput;
use crate::input::InputDefinition;
use crate::input::InputInterface;
+use crate::input::InputOptionValue;
use crate::input::StreamableInputInterface;
use indexmap::IndexMap;
use shirabe_php_shim::{PhpMixed, php_regex, preg_match};
@@ -177,7 +178,7 @@ impl InputInterface for StringInput {
InputInterface::get_options(&self.inner)
}
- fn get_option(&self, name: &str) -> anyhow::Result<PhpMixed> {
+ fn get_option(&self, name: &str) -> anyhow::Result<InputOptionValue> {
self.inner.get_option(name)
}